diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/CounterProtocolBM.cpp b/CounterAcqBM/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..2aca849 --- /dev/null +++ b/CounterAcqBM/protocol/CounterProtocolBM.cpp @@ -0,0 +1,62 @@ +#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(","); + + 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).toLongLong(); + counterData->load = subList.at(5); + 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/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/CounterProtocolBM.cpp b/CounterAcqBM/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..2aca849 --- /dev/null +++ b/CounterAcqBM/protocol/CounterProtocolBM.cpp @@ -0,0 +1,62 @@ +#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(","); + + 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).toLongLong(); + counterData->load = subList.at(5); + 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/CounterAcqBM/protocol/CounterProtocolBM.h b/CounterAcqBM/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcqBM/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/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/CounterProtocolBM.cpp b/CounterAcqBM/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..2aca849 --- /dev/null +++ b/CounterAcqBM/protocol/CounterProtocolBM.cpp @@ -0,0 +1,62 @@ +#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(","); + + 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).toLongLong(); + counterData->load = subList.at(5); + 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/CounterAcqBM/protocol/CounterProtocolBM.h b/CounterAcqBM/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/dto/CounterDataDto.cpp b/CounterAcqBM/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..711911f --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,62 @@ +#include "CounterDataDto.h" +#include "common/utils/SettingConfig.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} + +QJsonObject CounterDataDto::toJSON() +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelClockValue * 1E-12)); + dataObj.insert("rawValue", QString("%1").arg(this->channelData)); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", this->channelId); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +QJsonObject CounterDataDto::toJSON(int i) +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("rawValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", (i + 1)); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +void CounterDataDto::clone(CounterDataDto *copy) +{ + copy->frameId = this->frameId; + copy->level = this->level; + copy->load = this->load; + copy->channelData = this->channelData; + copy->channelRefId = this->channelRefId; + copy->channelActive = this->channelActive; + copy->channelId = channelId; + copy->type = 0; + + copy->channelClockValue = this->channelClockValue; + + copy->rawFrame = this->rawFrame; + + copy->timestamp = this->timestamp; + copy->milisecond = this->milisecond; + copy->devCode = this->devCode; + copy->devStatus = this->devStatus; +} diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/CounterProtocolBM.cpp b/CounterAcqBM/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..2aca849 --- /dev/null +++ b/CounterAcqBM/protocol/CounterProtocolBM.cpp @@ -0,0 +1,62 @@ +#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(","); + + 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).toLongLong(); + counterData->load = subList.at(5); + 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/CounterAcqBM/protocol/CounterProtocolBM.h b/CounterAcqBM/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/dto/CounterDataDto.cpp b/CounterAcqBM/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..711911f --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,62 @@ +#include "CounterDataDto.h" +#include "common/utils/SettingConfig.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} + +QJsonObject CounterDataDto::toJSON() +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelClockValue * 1E-12)); + dataObj.insert("rawValue", QString("%1").arg(this->channelData)); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", this->channelId); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +QJsonObject CounterDataDto::toJSON(int i) +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("rawValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", (i + 1)); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +void CounterDataDto::clone(CounterDataDto *copy) +{ + copy->frameId = this->frameId; + copy->level = this->level; + copy->load = this->load; + copy->channelData = this->channelData; + copy->channelRefId = this->channelRefId; + copy->channelActive = this->channelActive; + copy->channelId = channelId; + copy->type = 0; + + copy->channelClockValue = this->channelClockValue; + + copy->rawFrame = this->rawFrame; + + copy->timestamp = this->timestamp; + copy->milisecond = this->milisecond; + copy->devCode = this->devCode; + copy->devStatus = this->devStatus; +} diff --git a/CounterAcqBM/protocol/dto/CounterDataDto.h b/CounterAcqBM/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..ff19375 --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.h @@ -0,0 +1,43 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include +#include +#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> + qlonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + double channelClockValue; // + + QList channelActiveArray; // xhts + QList channelDataArray; // xhts + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qlonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + + QJsonObject toJSON(); + QJsonObject toJSON(int i); + void clone(CounterDataDto * copy); + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/CounterProtocolBM.cpp b/CounterAcqBM/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..2aca849 --- /dev/null +++ b/CounterAcqBM/protocol/CounterProtocolBM.cpp @@ -0,0 +1,62 @@ +#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(","); + + 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).toLongLong(); + counterData->load = subList.at(5); + 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/CounterAcqBM/protocol/CounterProtocolBM.h b/CounterAcqBM/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/dto/CounterDataDto.cpp b/CounterAcqBM/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..711911f --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,62 @@ +#include "CounterDataDto.h" +#include "common/utils/SettingConfig.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} + +QJsonObject CounterDataDto::toJSON() +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelClockValue * 1E-12)); + dataObj.insert("rawValue", QString("%1").arg(this->channelData)); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", this->channelId); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +QJsonObject CounterDataDto::toJSON(int i) +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("rawValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", (i + 1)); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +void CounterDataDto::clone(CounterDataDto *copy) +{ + copy->frameId = this->frameId; + copy->level = this->level; + copy->load = this->load; + copy->channelData = this->channelData; + copy->channelRefId = this->channelRefId; + copy->channelActive = this->channelActive; + copy->channelId = channelId; + copy->type = 0; + + copy->channelClockValue = this->channelClockValue; + + copy->rawFrame = this->rawFrame; + + copy->timestamp = this->timestamp; + copy->milisecond = this->milisecond; + copy->devCode = this->devCode; + copy->devStatus = this->devStatus; +} diff --git a/CounterAcqBM/protocol/dto/CounterDataDto.h b/CounterAcqBM/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..ff19375 --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.h @@ -0,0 +1,43 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include +#include +#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> + qlonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + double channelClockValue; // + + QList channelActiveArray; // xhts + QList channelDataArray; // xhts + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qlonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + + QJsonObject toJSON(); + QJsonObject toJSON(int i); + void clone(CounterDataDto * copy); + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcqBM/protocol/protocol.pri b/CounterAcqBM/protocol/protocol.pri new file mode 100644 index 0000000..ef4b391 --- /dev/null +++ b/CounterAcqBM/protocol/protocol.pri @@ -0,0 +1,8 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +#SOURCES += $$PWD/CounterProtocolXH.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +#HEADERS += $$PWD/CounterProtocolXH.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcq/CounterDevice.cpp b/CounterAcq/CounterDevice.cpp index 588b01d..ae2ccd4 100644 --- a/CounterAcq/CounterDevice.cpp +++ b/CounterAcq/CounterDevice.cpp @@ -7,7 +7,9 @@ CounterDevice::CounterDevice(QObject *parent) : QObject(parent) { this->udpClient = new QUdpSocket(this); - udpClient->bind(QHostAddress("192.168.1.213"), 8089); +// udpClient->bind(QHostAddress("192.168.1.213"), 8089, QUdpSocket::ShareAddress); + udpClient->writeDatagram("hello", QHostAddress("192.168.1.213"), 8089); + connect(udpClient, &QUdpSocket::readyRead, this, &CounterDevice::dataReceivedHandlerByUDP); diff --git a/CounterAcq/conf/config.ini b/CounterAcq/conf/config.ini index ebe1e82..da0eacf 100644 --- a/CounterAcq/conf/config.ini +++ b/CounterAcq/conf/config.ini @@ -9,6 +9,7 @@ [client] clientId="clock" appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" [http] baseUrl="http://111.198.10.15:11410" diff --git a/CounterAcq/protocol/protocol.pri b/CounterAcq/protocol/protocol.pri index 8aa7808..9194ddc 100644 --- a/CounterAcq/protocol/protocol.pri +++ b/CounterAcq/protocol/protocol.pri @@ -1,8 +1,8 @@ -#SOURCES += $$PWD/CounterProtocolBM.cpp +SOURCES += $$PWD/CounterProtocolBM.cpp SOURCES += $$PWD/CounterProtocolXH.cpp SOURCES += $$PWD/dto/CounterDataDto.cpp -#HEADERS += $$PWD/CounterProtocolBM.h +HEADERS += $$PWD/CounterProtocolBM.h HEADERS += $$PWD/CounterProtocolXH.h HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/CounterAcqBM/CounterAcqBM.pro b/CounterAcqBM/CounterAcqBM.pro new file mode 100644 index 0000000..38de4cb --- /dev/null +++ b/CounterAcqBM/CounterAcqBM.pro @@ -0,0 +1,29 @@ +QT += core gui serialport network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +FORMS += CounterWindow.ui + +include(common/common.pri) +include(protocol/protocol.pri) + +HEADERS += CounterDevice.h +HEADERS += CounterWindow.h + +SOURCES += CounterDevice.cpp +SOURCES += CounterWindow.cpp +SOURCES += main.cpp + +DISTFILES += conf/config.ini + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +unix:!macx: LIBS += -L$$PWD/lib/librdkafka/ -lrdkafka -lrdkafka++ + +INCLUDEPATH += $$PWD/include/librdkafka +DEPENDPATH += $$PWD/include/librdkafka diff --git a/CounterAcqBM/CounterDevice.cpp b/CounterAcqBM/CounterDevice.cpp new file mode 100644 index 0000000..8c43fc3 --- /dev/null +++ b/CounterAcqBM/CounterDevice.cpp @@ -0,0 +1,187 @@ +#include "CounterDevice.h" + +#include +#include +#include + +CounterDevice::CounterDevice(QObject *parent) : QObject(parent) +{ + connect(&this->serialUtil, &QSerialPortUtil::dataRecieved, + this, &CounterDevice::dataReceivedHandler); + + connect(this, &CounterDevice::successDataCalculate, + this, &CounterDevice::afterFramePhase); + + kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS); + kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC); + kafkaUtil.createProducer(); +} + +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; +} +void CounterDevice::setDeviceId(QString deviceId) +{ + this->deviceId = deviceId; +} + +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) + { + // 1. 清空dataBuff,等待下一帧的数据 + this->dataBuff.clear(); + + // 2. 补充其他字段 + QDateTime now = QDateTime::currentDateTime(); + counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz"); + counterData->milisecond = now.toMSecsSinceEpoch(); + counterData->devCode = devCode; + + this->afterFramePhase(counterData); + + // 3 计算数据ID一样的测量数据的时差值,通道值-参考通道值 + this->pushChannelRawFrame(counterData); + } + } + + // 在此处释放内存,不影响后续显示 + // 不在此处释放内存则会导致内存持续增加 + delete counterData; +} + +void CounterDevice::afterFramePhase(CounterDataDto * counterData) +{ + // 0. 输出到日志文件中 + QString date = counterData->timestamp.mid(0, 10); + + // 1. 原始字节数组数据 + QString filename = "raw_" + devCode + ".log"; + QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size()); + QLogUtil::writeRawDataLogByDate(date, filename, content); + + // 2. 各个通道的clock diff数据 + QString chFilename("%1_CH_%2.log"); + chFilename = chFilename.arg(devCode); + if (counterData->channelId < 10) + { + chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId)); + } else + { + chFilename = chFilename.arg(counterData->channelId); + } + QString channelDataStr = QString("%1 [%2] %3 %4") + .arg(counterData->timestamp) + .arg(counterData->frameId) + .arg(counterData->channelData) + .arg(counterData->channelClockValue); + QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr); + + // 3. 输出到中间件,执行后续处理过程 + if (SettingConfig::getInstance().NEED_KAFKA == 1) + { + QJsonObject jsonObj = counterData->toJSON(); + jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID); + jsonObj.insert("deviceId", deviceId); + kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact))); + } + + // 4. 在界面上简单显示相差数据结果 + emit this->sendDataToDraw(counterData); +} + +void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData) +{ + QString currentFrameId = counterData->frameId; + QString currentChannelId = QString("%1").arg(counterData->channelId); + + if (counterData->channelId == counterData->channelRefId) + { + // 自身是参考通道 + bench.insert(currentFrameId, counterData->channelData); + counterData->channelClockValue = 0; + + emit successDataCalculate(counterData); + + qlonglong thisBench = counterData->channelData; + // 遍历temp,处理之前的临时暂存的队列 + if (hisList.isEmpty() == false) + { + for (int i = 0; i < hisList.size(); i++) + { + CounterDataDto * hisItem = hisList.at(i); + if (hisItem->frameId == currentFrameId) + { + hisItem->channelClockValue = (hisItem->channelData - thisBench) * 10; + + emit successDataCalculate(hisItem); + delete hisItem; + } + } + + hisList.clear(); + } + } else + { + // 自身不是参考通道,减去相同frameId的参考通道值 + if (bench.contains(currentFrameId) == true) + { + // 在参考基准中能找到 + qlonglong currentBench = bench.find(currentFrameId).value(); + counterData->channelClockValue = (counterData->channelData - currentBench) * 10; // 10ps + + emit successDataCalculate(counterData); + } else + { + // 暂存,等收到基准之后再处置 + CounterDataDto * copyPoint = new CounterDataDto(); + + // ★clone一份对象,存入缓存队列 + counterData->clone(copyPoint); + + hisList.append(copyPoint); + } + } +} diff --git a/CounterAcqBM/CounterDevice.h b/CounterAcqBM/CounterDevice.h new file mode 100644 index 0000000..654a96d --- /dev/null +++ b/CounterAcqBM/CounterDevice.h @@ -0,0 +1,54 @@ +#ifndef COUNTERDEVICE_H +#define COUNTERDEVICE_H + +#include + +#include "common/utils/QSerialPortUtil.h" +#include "common/utils/QKafkaUtil.h" +#include "common/utils/QByteUtil.h" +#include "common/utils/QLogUtil.h" +#include "common/utils/SettingConfig.h" +#include "protocol/CounterProtocolBM.h" + +class CounterDevice : public QObject +{ + Q_OBJECT +public: + explicit CounterDevice(QObject *parent = nullptr); + ~CounterDevice(); + + void initSerialPort(); + + void setComName(QString comName); + void setBaudRate(int baudRate); + QString getDevCode(); + void setDevCode(QString devCode); + void setDeviceId(QString deviceId); + + bool isSerialOpen(); + +private: + QString deviceId; + QString devCode; + QString comName; + int baudRate; + + QSerialPortUtil serialUtil; + QKafkaUtil kafkaUtil; + QByteArray dataBuff; + + QMap bench; + QList hisList; + + void pushChannelRawFrame(CounterDataDto * counterData); + +signals: + void sendDataToDraw(CounterDataDto * counterData); + void successDataCalculate(CounterDataDto * counterData); + +public slots: + void dataReceivedHandler(QByteArray data); + void afterFramePhase(CounterDataDto * counterData); +}; + +#endif // COUNTERDEVICE_H diff --git a/CounterAcqBM/CounterWindow.cpp b/CounterAcqBM/CounterWindow.cpp new file mode 100644 index 0000000..1dc37bf --- /dev/null +++ b/CounterAcqBM/CounterWindow.cpp @@ -0,0 +1,260 @@ +#include "CounterWindow.h" +#include "ui_CounterWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CounterWindow::CounterWindow(QWidget *parent) : + QWidget(parent), + ui(new Ui::CounterWindow) +{ + ui->setupUi(this); + + // 无边框 + this->setWindowFlags(Qt::FramelessWindowHint); + + // 窗口大小为占满一屏 + QRect screenRect = QApplication::desktop()->screenGeometry(); + resize(screenRect.width(), screenRect.height()); + + // 将窗口移动到左上角 + move(0, 0); + ui->exitButt->move(screenRect.width() - 80, 10); + ui->minButt->move(screenRect.width() - 140, 10); + ui->line->setGeometry(0, 59, screenRect.width(), 1); + + // 设置主体区域的大小和位置 + ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60); + ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + httpReq = new HttpRequestController(this); + // 1. 获取访问接口需要的token + int retCode = this->initHttpToken(); + if (retCode != 200) + { + QMessageBox::information(this, "错误", "获取http请求的token失败,程序即将退出"); + + QTimer::singleShot(1000, qApp, SLOT(quit())); + } + // 2. 获取字典值:设备类型 + retCode = this->initDictDeviceTypes(); + + // 3. 获取计数器设备列表 + QJsonObject devListRes = this->initDeviceList(); + if (devListRes.find("code")->toInt() == 200) + { + ui->devSelect->clear(); + + // 4. 将获取到的设备添加到下拉列表框中 + QJsonArray devArray = devListRes.find("data")->toArray(); + for (int i =0; i < 1; i++) + { + QJsonObject devItem = devArray.at(i).toObject(); + ui->devSelect->addItem(devItem.find("deviceName")->toString(), devItem.find("deviceNo")->toString()); + + CounterDevice * device = new CounterDevice(this); + deviceList.append(device); + + device->setComName(devItem.find("linkComName")->toString()); + device->setBaudRate(SettingConfig::getInstance().BAUD_RATE); + device->setDevCode(devItem.find("deviceNo")->toString()); + device->setDeviceId(devItem.find("deviceId")->toString()); + + connect(device, &CounterDevice::sendDataToDraw, + this, &CounterWindow::drawCounterDataOnPage); + +// device->initSerialPort(); + + QThread::msleep(200); + } + // 5. 设置下拉框的样式 + QStandardItemModel * model = qobject_cast(ui->devSelect->model()); + for (int i = 0; i < model->rowCount(); ++i) + { + QStandardItem * item = model->item(i); + item->setSizeHint({ 0, 30 }); + } + } + + // 6. 绘制一个设备的多个通道数据面板 + this->generateWidgetForDevice(); +} + +CounterWindow::~CounterWindow() +{ + delete ui; +} + +void CounterWindow::generateWidgetForDevice() +{ + // 获取设备数据 + int channelNum = 16; + + QRect screenRect = QApplication::desktop()->screenGeometry(); + + ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90); + + QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents); + const QFont labelFont("微软雅黑", 10); + + for (int i = 0; i < channelNum; i++) + { + QGroupBox * group = new QGroupBox(ui->scrollContents); + group->setTitle(QString("通道 - %1").arg(i + 1)); + group->setFont(QFont("微软雅黑", 12)); + group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80); + + QHBoxLayout * vbox = new QHBoxLayout(group); + + QLabel * tmLabel = new QLabel(); + tmLabel->setText("时间"); + tmLabel->setFont(labelFont); + tmLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(tmLabel); + QLineEdit * tmValue = new QLineEdit(); + tmValue->setFixedWidth(200); + tmValue->setFont(labelFont); + vbox->addWidget(tmValue); + + QLabel * dataLabel = new QLabel(); + dataLabel->setText("测量数据"); + dataLabel->setFont(labelFont); + dataLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(dataLabel); + QLineEdit * dataValue = new QLineEdit(); + dataValue->setFixedWidth(75); + dataValue->setFont(labelFont); + vbox->addWidget(dataValue); + + QLabel * idLabel = new QLabel(); + idLabel->setText("数据ID"); + idLabel->setFont(labelFont); + idLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(idLabel); + QLineEdit * idValue = new QLineEdit(); + idValue->setFixedWidth(75); + idValue->setFont(labelFont); + vbox->addWidget(idValue); + + QLabel * refChLabel = new QLabel(); + refChLabel->setText("参考通道"); + refChLabel->setFont(labelFont); + refChLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(refChLabel); + QLineEdit * refChValue = new QLineEdit(); + refChValue->setFixedWidth(60); + refChValue->setFont(labelFont); + vbox->addWidget(refChValue); + + QLabel * loadLabel = new QLabel(); + loadLabel->setText("负载"); + loadLabel->setFont(labelFont); + loadLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(loadLabel); + QLineEdit * loadValue = new QLineEdit(); + loadValue->setFixedWidth(60); + loadValue->setFont(labelFont); + vbox->addWidget(loadValue); + + QLabel * levelLabel = new QLabel(); + levelLabel->setText("触发电平"); + levelLabel->setFont(labelFont); + levelLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(levelLabel); + QLineEdit * levelValue = new QLineEdit(); + levelValue->setFixedWidth(60); + levelValue->setFont(labelFont); + vbox->addWidget(levelValue); + + QLabel * validLabel = new QLabel(); + validLabel->setText("-"); + validLabel->setFont(labelFont); + validLabel->setStyleSheet("margin-left:20;"); + vbox->addWidget(validLabel); + + QSpacerItem * hSpace = new QSpacerItem(20, 20); + hSpace->changeSize(20, 20, QSizePolicy::Expanding); + vbox->addItem(hSpace); + + group->setLayout(vbox); + + layout->addWidget(group); + } +} + +void CounterWindow::drawCounterDataOnPage(CounterDataDto * counterData) +{ + // 当前显示的设备编号 + QString currentDevCode = ui->devSelect->currentData().toString(); + + // 如果不是当前设备的帧,直接返回 + if (counterData->devCode != currentDevCode) + { + return; + } + + // 1. 判断数据属于哪个设备,显示在不同的widget上 +// qDebug() << counterData->toJSON() << counterData->devCode << "---" << counterData->frameId; + + // 更新所有通道BOX的值 + for (int i = 0; i < counterData->channelDataArray.size(); i++) + { + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(counterData->channelDataArray.at(i))); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActiveArray.at(i) == "1" ? "有效" : "无效"); + } + /* + // 获取对应的通道BOX + QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(counterData->channelId); + + // 赋值,对应的lineEdit/label + ((QLineEdit *)channelBox->children().at(2))->setText(counterData->timestamp); + ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 ps").arg(counterData->channelClockValue)); + ((QLineEdit *)channelBox->children().at(6))->setText(counterData->frameId); + ((QLineEdit *)channelBox->children().at(8))->setText(QString("%1").arg(counterData->channelRefId)); + ((QLineEdit *)channelBox->children().at(10))->setText(QString("%1 Ω").arg(counterData->load == 1 ? "1M" : "50")); + ((QLineEdit *)channelBox->children().at(12))->setText(QString("%1 V").arg(counterData->level)); + ((QLabel *)channelBox->children().at(13))->setText(counterData->channelActive == 1 ? "有效" : "无效"); + */ +} + +int CounterWindow::initHttpToken() +{ + QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID, + SettingConfig::getInstance().APP_KEY); + return response.find("code")->toInt(); +} +int CounterWindow::initDictDeviceTypes() +{ + QJsonObject response = httpReq->initDictDeviceType(); + return response.find("code")->toInt(); +} +QJsonObject CounterWindow::initDeviceList() +{ + QJsonObject response = httpReq->initDeviceList("计数器"); + return response; +} + +void CounterWindow::on_exitButt_clicked() +{ + QApplication::exit(0); +} + +void CounterWindow::on_minButt_clicked() +{ + setWindowState(Qt::WindowMinimized | windowState()); +} diff --git a/CounterAcqBM/CounterWindow.h b/CounterAcqBM/CounterWindow.h new file mode 100644 index 0000000..09277ba --- /dev/null +++ b/CounterAcqBM/CounterWindow.h @@ -0,0 +1,47 @@ +#ifndef COUNTERWINDOW_H +#define COUNTERWINDOW_H + +#include +#include +#include +#include + +#include "common/utils/SettingConfig.h" +#include "common/HttpRequestController.h" +#include "CounterDevice.h" + +namespace Ui { +class CounterWindow; +} + +class CounterWindow : public QWidget +{ + Q_OBJECT + +public: + explicit CounterWindow(QWidget *parent = nullptr); + ~CounterWindow(); + +public slots: + void drawCounterDataOnPage(CounterDataDto * counterData); + +private slots: + void on_exitButt_clicked(); + + void on_minButt_clicked(); + +private: + int initHttpToken(); + int initDictDeviceTypes(); + QJsonObject initDeviceList(); + + Ui::CounterWindow *ui; + + HttpRequestController * httpReq; + + QList deviceList; + + void generateWidgetForDevice(); +}; + +#endif // COUNTERWINDOW_H diff --git a/CounterAcqBM/CounterWindow.ui b/CounterAcqBM/CounterWindow.ui new file mode 100644 index 0000000..9ac6eb3 --- /dev/null +++ b/CounterAcqBM/CounterWindow.ui @@ -0,0 +1,156 @@ + + + CounterWindow + + + + 0 + 0 + 1024 + 720 + + + + 多通道计数器数据采集 + + + + + 0 + 0 + 100 + 30 + + + + + 微软雅黑 + 10 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 100 + 30 + + + + + + + + 400 + 10 + 250 + 40 + + + + + + + 250 + 0 + 150 + 60 + + + + + 微软雅黑 + 12 + + + + Qt::LeftToRight + + + 请选择计数器 + + + Qt::AlignCenter + + + + + + 880 + 10 + 40 + 40 + + + + + + + 退出 + + + + + + 20 + 0 + 200 + 60 + + + + + 微软雅黑 + 14 + + + + 多通道计数器数据采集 + + + + + + 0 + 59 + 1024 + 1 + + + + QFrame::Plain + + + Qt::Horizontal + + + + + + 830 + 10 + 40 + 40 + + + + + + + 最小化 + + + + + + diff --git a/CounterAcqBM/common/ConstCache.h b/CounterAcqBM/common/ConstCache.h new file mode 100644 index 0000000..6cc831b --- /dev/null +++ b/CounterAcqBM/common/ConstCache.h @@ -0,0 +1,30 @@ +#ifndef CONSTCACHE_H +#define CONSTCACHE_H + +#include +#include +#include +#include + +class ConstCache : public QObject +{ + Q_OBJECT +public: + ~ConstCache() {}; + ConstCache(const ConstCache&)=delete; + ConstCache& operator=(const ConstCache&)=delete; + + static ConstCache& getInstance() { + static ConstCache instance; + return instance; + } + + QMap deviceTypes; + QList deviceList; + +private: + ConstCache() {}; + +}; + +#endif // CONSTCACHE_H diff --git a/CounterAcqBM/common/HttpRequestController.cpp b/CounterAcqBM/common/HttpRequestController.cpp new file mode 100644 index 0000000..d4912b8 --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.cpp @@ -0,0 +1,157 @@ +#include "HttpRequestController.h" + +HttpRequestController::HttpRequestController(QObject *parent) : QObject(parent) +{ + httpUtil = new HttpRequestUtil(this); + baseUrl = SettingConfig::getInstance().getProperty("http", "baseUrl").toString(); + system = SettingConfig::getInstance().getProperty("client", "clientId").toString(); +} + +QJsonObject HttpRequestController::getTokenByClientId(QString clientId, QString key) +{ + QJsonObject resultObj; + + // 获取token的url地址 + QUrl url = baseUrl + "/getTokenByClientId"; + + // 请求对象 + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + + // 生成随机数作为salt + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + float random = (qrand() % 10000) / (float)10000; + QString salt = QByteUtil::binToHexString(QByteUtil::floatToBytes(random)); + QString clientSecret = clientId + "_" + key + "_" + salt; + + // MD5加密clientSecret + char secretEn[CHAR_MD5_LEN]; + MD5::MD5Encode(clientSecret.toStdString().data(), clientSecret.length(), secretEn); + QString secretMD5(secretEn); + + QJsonObject paramObj; + paramObj.insert("clientId", clientId); + paramObj.insert("salt", salt); + paramObj.insert("clientSecret", secretMD5); + QJsonDocument document; + document.setObject(paramObj); + QByteArray content = document.toJson(QJsonDocument::Compact); + + QNetworkReply * reply = httpUtil->sendPostRequest(request, content); + + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + QString token = resultObj.find("data")->toString(); + this->token = token; + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDictDeviceType() +{ + QJsonObject resultObj; + + // 获取字典值的接口地址 + QUrl url = baseUrl + "/sys/dict/code/deviceType"; + + // + QNetworkRequest request; + request.setUrl(url); + + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceTypes.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceTypes.insert(item.find("value")->toString(), item.find("name")->toString()); + } + } + } else + { + resultObj.insert("code", -1); + } + + return resultObj; +} + +QJsonObject HttpRequestController::initDeviceList(QString devType) +{ + QJsonObject resultObj; + + QString counterDevType = ""; + QMapIterator it(ConstCache::getInstance().deviceTypes); + while (it.hasNext()) + { + it.next(); + if (it.value().contains(devType) == true) + { + counterDevType = it.key(); + break; + } + } + + // 获取设备列表的接口地址 + QUrl url = baseUrl + "/device/list"; + QUrlQuery query; + query.addQueryItem("type", counterDevType); + url.setQuery(query); + + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("Content-type", "application/json"); + request.setRawHeader("token", token.toLocal8Bit()); + request.setRawHeader("system", system.toLocal8Bit()); + + qDebug() << url; + + QNetworkReply * reply = httpUtil->sendGetRequest(request); + const QByteArray reply_data = reply->readAll(); + QJsonDocument jsonDocument = QJsonDocument::fromJson(reply_data); + if(jsonDocument.isNull() == false) { + resultObj = jsonDocument.object(); + + if (resultObj.find("code")->toInt() == 200) + { + ConstCache::getInstance().deviceList.clear(); + + QJsonArray data = resultObj.find("data")->toArray(); + for (int i = 0; i < data.size(); i++) + { + QJsonObject item = data.at(i).toObject(); + + ConstCache::getInstance().deviceList.append(item); + } + } + } else + { + resultObj.insert("code", -1); + } + + qDebug() << resultObj; + + return resultObj; +} diff --git a/CounterAcqBM/common/HttpRequestController.h b/CounterAcqBM/common/HttpRequestController.h new file mode 100644 index 0000000..77fc3db --- /dev/null +++ b/CounterAcqBM/common/HttpRequestController.h @@ -0,0 +1,35 @@ +#ifndef HTTPREQUESTCONTROLLER_H +#define HTTPREQUESTCONTROLLER_H + +#include +#include + +#include "utils/HttpRequestUtil.h" +#include "utils/SettingConfig.h" +#include "utils/MD5.h" +#include "utils/QByteUtil.h" +#include "ConstCache.h" + +class HttpRequestController : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestController(QObject *parent = nullptr); + + QJsonObject getTokenByClientId(QString clientId, QString key); + QJsonObject initDictDeviceType(); + QJsonObject initDeviceList(QString devType); + +private: + HttpRequestUtil * httpUtil; + + QString baseUrl; + + QString token; + QString system; + +signals: + +}; + +#endif // HTTPREQUESTCONTROLLER_H diff --git a/CounterAcqBM/common/common.pri b/CounterAcqBM/common/common.pri new file mode 100644 index 0000000..6280f64 --- /dev/null +++ b/CounterAcqBM/common/common.pri @@ -0,0 +1,20 @@ + +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 +SOURCES += $$PWD/utils/HttpRequestUtil.cpp +SOURCES += $$PWD/utils/MD5.cpp +SOURCES += $$PWD/HttpRequestController.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 +HEADERS += $$PWD/utils/HttpRequestUtil.h +HEADERS += $$PWD/utils/DefHead.h +HEADERS += $$PWD/utils/MD5.h +HEADERS += $$PWD/HttpRequestController.h +HEADERS += $$PWD/ConstCache.h diff --git a/CounterAcqBM/common/utils/DefHead.h b/CounterAcqBM/common/utils/DefHead.h new file mode 100644 index 0000000..2171b0e --- /dev/null +++ b/CounterAcqBM/common/utils/DefHead.h @@ -0,0 +1,59 @@ +/***********************************************Copyright:Pluviophile******************************************/ +/**********************************************Email:1565203609@qq.com*****************************************/ +#pragma once + +#define _In_ +#define _Inout_ +#define SOCKET_ERROR -1 + +#define cu_long unsigned long +#define cu_char unsigned char +#define cu_int unsigned int +#define cu_short unsigned short + +#define __ERROR 0X00000 +#define __SUCCESS 0X00001 +//PE FILE DEFINE +#define __FILE_OPEN_ERROR 0X00002 +#define __FILE_READ_ERROR 0X00003 +#define __FILE_NO_PE 0X00004 +#define __FILE_NO_NT 0X00005 +#define __FILE_SAVE_ERROR 0X00006 +#define __FILE_WRITE_ERROR 0X00007 +#define __LASTSECTION_NO_NULL 0X00008 +#define __FILE_WRITESIZE_MISMATCH 0X00009 +#define __FILE_TOO_BIG 0X0000A + +#define __SECTION_SIZE 0X00028 + +#define __I386_FILE_MAX 0XFFFFFFFF + +//UDPSocket DEINE +#define __SOCK_WSAINIT_ERROR 0X0000B +#define __SOCK_INIT_ERROR __SOCK_WSAINIT_ERROR+1 +#define __SOCK_PORT_ERROR __SOCK_WSAINIT_ERROR+2 +#define __SOCK_IP_ERROR __SOCK_WSAINIT_ERROR+3 +#define __SOCK_LISTEN_ERROR __SOCK_WSAINIT_ERROR+4 +#define __SOCKET_CLOSE_ERROR __SOCK_WSAINIT_ERROR+5 +#define __SOCKET_LISTENNUM_TOOBIG __SOCK_WSAINIT_ERROR+6 +#define __SOCK_ACCEPT_ERROR __SOCK_WSAINIT_ERROR+7 +#define __SOCK_CONNECT_ERROR __SOCK_WSAINIT_ERROR+8 +#define __SOCK_IP_ISNULL __SOCK_WSAINIT_ERROR+9 +#define __SOCKET_NO_RECV __SOCK_WSAINIT_ERROR+10 +#define __SOCKET_SEND_ERROR __SOCK_WSAINIT_ERROR+11 +#define __SOCKET_RECV_ERROR __SOCK_WSAINIT_ERROR+12 + +//base64 +#define __BASE_NO_BASE64 0X00018 + +//SMTP +#define __SMTP_ERROR 0X00019 +#define __SMTP_HELO_ERROR __SMTP_ERROR+1 +#define __SMTP_AUTH_ERROR __SMTP_ERROR+2 +#define __SMTP_USERPASSWD_ERROR __SMTP_ERROR+3 +#define __SMTP_PASSWD_ERROR __SMTP_ERROR+4 +#define __SMTP_FROM_ERROR __SMTP_ERROR+5 +#define __SMTP_RECPTO_ERROR __SMTP_ERROR+6 +#define __SMTP_QUIT_ERROR __SMTP_ERROR+7 +#define __SMTP_DATAFLAG_ERROR __SMTP_ERROR+8 +#define __SMTP_EMAILSEND_ERROR __SMTP_ERROR+9 \ No newline at end of file diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.cpp b/CounterAcqBM/common/utils/HttpRequestUtil.cpp new file mode 100644 index 0000000..e537083 --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.cpp @@ -0,0 +1,33 @@ +#include "HttpRequestUtil.h" + +HttpRequestUtil::HttpRequestUtil(QObject *parent) : QObject(parent) +{ + manager = new QNetworkAccessManager(this); +} + + +QNetworkReply * HttpRequestUtil::sendGetRequest(QNetworkRequest request) +{ + //发送请求 + QNetworkReply * reply = manager->get(request); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} + +QNetworkReply * HttpRequestUtil::sendPostRequest(QNetworkRequest request, QByteArray params) +{ + //发送请求 + QNetworkReply * reply = manager->post(request, params); + + // 同步等待 + QEventLoop eventLoop; + connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit); + eventLoop.exec(); + + return reply; +} diff --git a/CounterAcqBM/common/utils/HttpRequestUtil.h b/CounterAcqBM/common/utils/HttpRequestUtil.h new file mode 100644 index 0000000..ee0478b --- /dev/null +++ b/CounterAcqBM/common/utils/HttpRequestUtil.h @@ -0,0 +1,28 @@ +#ifndef HTTPREQUESTUTIL_H +#define HTTPREQUESTUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class HttpRequestUtil : public QObject +{ + Q_OBJECT +public: + explicit HttpRequestUtil(QObject *parent = nullptr); + + QNetworkAccessManager * manager; + + QNetworkReply * sendGetRequest(QNetworkRequest request); + QNetworkReply * sendPostRequest(QNetworkRequest request, QByteArray params); + +signals: + +}; + +#endif // HTTPREQUESTUTIL_H diff --git a/CounterAcqBM/common/utils/MD5.cpp b/CounterAcqBM/common/utils/MD5.cpp new file mode 100644 index 0000000..dc422ca --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.cpp @@ -0,0 +1,144 @@ +#include"MD5.h" + +MD5::MD5() +{ + nullptr; +} + +void MD5::MD5Encode +( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst +) +{ + //用于存放最终结果,以便转化为字符串 + short output[16]; + char dest[16]; + memset(dest, 0, SHORT_MD5_LEN); + memset(dst, 0, CHAR_MD5_LEN); + //四组幻数 + unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + static const unsigned int k[64] = + { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + //四轮循环(GG,FF,HH,II)每轮循环每一步所要位移的位数 + static const unsigned int qz[] = + { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + //每一轮所要读取的元素下表 + static const unsigned int s[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 + }; + + unsigned int i = 0, j = 0; + //N*512+448 + //N=(数据长度+64(bit))/512(bit),长度+8是为了防止数据长度>=56 + //任意数据长度+64bit刚好是512倍数,最后+8空出存放数据原始长度的位置 + size_t n_len = ((len + 8) / 64) * 64 + 56 + 8; + unsigned char *n_text = (unsigned char *)malloc(n_len); + memset(n_text, 0x00, n_len); + memcpy(n_text, text, len); + //末尾添加二进制1000 0000 + n_text[len] = 0x80; + //追加长度 + //注意此处末尾添加的是一个64位的数据!!! + unsigned char len_s[8]; + memset(len_s, 0x00, 8); + unsigned long temp_len = 0x00000000; + temp_len = (unsigned long)(len * 8); + //此处注意,只拷贝4个字节数据,因为 + //unsigned long只有四个字节 + memcpy(len_s, &temp_len, 4); + memcpy(n_text + (n_len-8), len_s, 8); + + //每64字节(512位) + //处理一次,因为填充过后的数刚好是64的倍数 + for (j = 0; j < n_len; j += 64) + { + unsigned int H[4] = { 0,0,0,0 }; + memcpy(H, h, 4 * sizeof(unsigned int)); + //分段拷贝内容,以供处理多组数据 + unsigned char temp_text[64]; + memset(temp_text, 0x00, 64); + memcpy(temp_text, n_text + j, 64); + + //一共循环64次,分为四组 + for (i = 0; i < 64; i++) + { + //四组非线性函数运算,用开关语句来判断是第几组 + // 0~16第一组,16~32第二组 + //32~48第三组,48~64第四组 + unsigned int R = 0, f = 0, tmp = 0; + switch ((int)i / 16) + { + //H[1]=X,H[2]=Y,H[3]=Z + //F(X,Y,Z) + case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break; + //G(X,Y,Z) + case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break; + //H(X,Y,Z) + case 2: f = H[1] ^ H[2] ^ H[3]; break; + //I + case 3: f = H[2] ^ (H[1] | (~H[3])); break; + } + //abcd分别交换位置 + tmp = H[3]; + H[3] = H[2]; + H[2] = H[1]; + //R=(a+?(bcd)+M?+ti),四个字节一运算不是一个字节 + R = H[0] + f + k[i] + (((unsigned int *)temp_text)[s[i]]); + //b+((a+?(bcd)+M?+ti)<> (32 - qz[i]))); + H[0] = tmp; + } + //每轮循环结束后,ABCD分别与abcd相加 + for (i = 0; i < 4; i++) h[i] += H[i]; + } + + free(n_text); + memcpy(dest, h, 16); + + //与0xff位与将高位的ff变为00 + for (int i = 0; i < 16; i++) + output[i] = dest[i] & 0xff; + //将十六进制数据打印成字符串 + for (int i = 0; i < SHORT_MD5_LEN; i++) + sprintf(dst + i * 2, "%02x", output[i]); +} + + +bool MD5::MD5StrValidate +( + _In_ const char * input1, + _In_ const char * input2 +) +{ + if (strcmp(input1, input2) == 0) + return true; + return false; +} diff --git a/CounterAcqBM/common/utils/MD5.h b/CounterAcqBM/common/utils/MD5.h new file mode 100644 index 0000000..5d86d32 --- /dev/null +++ b/CounterAcqBM/common/utils/MD5.h @@ -0,0 +1,33 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include"DefHead.h" + +#define SHORT_MD5_LEN 16 +#define CHAR_MD5_LEN 34 + + +class MD5 +{ +public: + explicit MD5(); + static void MD5Encode + ( + _In_ const char* text, + _In_ size_t len, + _Inout_ char* dst + ); + + static bool MD5StrValidate + ( + _In_ const char* input1, + _In_ const char* input2 + ); +private: + ; +}; + +#endif // !MD5_H diff --git a/CounterAcqBM/common/utils/QByteUtil.cpp b/CounterAcqBM/common/utils/QByteUtil.cpp new file mode 100644 index 0000000..b26c69b --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QByteUtil.h b/CounterAcqBM/common/utils/QByteUtil.h new file mode 100644 index 0000000..78fe0dd --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/common/utils/QKafkaUtil.cpp b/CounterAcqBM/common/utils/QKafkaUtil.cpp new file mode 100644 index 0000000..3f00452 --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.cpp @@ -0,0 +1,59 @@ +#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::createProducer() +{ + 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; +} + +int QKafkaUtil::produceMessage(QString message) +{ + auto retCode = producer->produce(topic.toStdString(), RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, + const_cast(message.toStdString().c_str()), message.size(), + nullptr, 0, 0, nullptr, nullptr); + + if (retCode != RdKafka::ERR_NO_ERROR) + { + std::cerr << "Failed to produce to topic " << topic.toStdString() << ": " << + RdKafka::err2str(retCode) << std::endl; + } else + { + std::cerr << "Enqueued message (" << message.size() << " bytes) " << + "for topic " << topic.toStdString() << "[" << message.toStdString() <<"]" << std::endl; + } + + return retCode; +} diff --git a/CounterAcqBM/common/utils/QKafkaUtil.h b/CounterAcqBM/common/utils/QKafkaUtil.h new file mode 100644 index 0000000..289ea6f --- /dev/null +++ b/CounterAcqBM/common/utils/QKafkaUtil.h @@ -0,0 +1,33 @@ +#ifndef QKAFKAUTIL_H +#define QKAFKAUTIL_H + +#include + +#include "include/librdkafka/rdkafkacpp.h" + +class QKafkaUtil : public QObject +{ + Q_OBJECT +public: + explicit QKafkaUtil(QObject *parent = nullptr); + + void setBrokers(QString brokers); + void setTopic(QString topic); + + int createProducer(); + int produceMessage(QString message); + +private: + QString brokers; + QString topic; + + std::string errStr; + + RdKafka::Conf * conf; + + RdKafka::Producer * producer = 0; +signals: + +}; + +#endif // QKAFKAUTIL_H diff --git a/CounterAcqBM/common/utils/QLogUtil.cpp b/CounterAcqBM/common/utils/QLogUtil.cpp new file mode 100644 index 0000000..43d8655 --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.cpp @@ -0,0 +1,92 @@ +#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) +{ + +} + +void QLogUtil::writeRawDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile rawLogFile(datePath + filename); + rawLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + rawLogFile.write(content.toUtf8()); + rawLogFile.close(); +} + +void QLogUtil::writeChannelDataLogByDate(QString date, QString filename, QString content) +{ + QString basePath = SettingConfig::getInstance().BASE_LOG_PATH; + QString datePath = basePath + date + "/"; + + QStringList pathList; + pathList.append(basePath); + pathList.append(datePath); + + // 检查并创建目录 + QLogUtil::checkLogPath(pathList); + + // 输出内容到日志中 + content.append("\n"); + QFile chLogFile(datePath + filename); + chLogFile.open(QIODevice::ReadWrite|QIODevice::Append|QIODevice::Text); + chLogFile.write(content.toUtf8()); + chLogFile.close(); +} + +void QLogUtil::checkLogPath(QStringList path) +{ + QDir dir; + bool exist = false; + + for (int i = 0; i < path.size(); i++) + { + // 判断是否存在日志根目录 + exist = dir.exists(path.at(i)); + if (exist == false) + { + // 不存在则创建目录 + dir.mkdir(path.at(i)); + } + } +} diff --git a/CounterAcqBM/common/utils/QLogUtil.h b/CounterAcqBM/common/utils/QLogUtil.h new file mode 100644 index 0000000..1d1ef0f --- /dev/null +++ b/CounterAcqBM/common/utils/QLogUtil.h @@ -0,0 +1,30 @@ +#ifndef QLOGUTIL_H +#define QLOGUTIL_H + +#include +#include +#include +#include +#include "SettingConfig.h" + +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); + + static void writeRawDataLogByDate(QString date, QString filename, QString content); + static void writeChannelDataLogByDate(QString date, QString filename, QString content); + +private: + static void checkLogPath(QStringList path); +signals: + +}; + +#endif // QLOGUTIL_H diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.cpp b/CounterAcqBM/common/utils/QSerialPortUtil.cpp new file mode 100644 index 0000000..1710f93 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.cpp @@ -0,0 +1,115 @@ +#include "QSerialPortUtil.h" + +#include +#include +#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); + + // mock data received per second + QTimer * timer = new QTimer(this); + connect(timer, &QTimer::timeout, + this, &QSerialPortUtil::mockReceivData); + timer->start(1000); +// } +} + +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; +} + +void QSerialPortUtil::mockReceivData() +{ + QDateTime now = QDateTime::currentDateTime(); + + QByteArray buffer; + buffer.append("$XHTS"); + buffer.append("03100010"); + buffer.append(now.toString("yyMMddHHmmss")); + buffer.append("276"); + + qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + QByteArray statusBuff; + QByteArray dataBuff; + + QString validStr = "1111010111001011"; + + statusBuff.append("|").append("1").append(validStr.toLocal8Bit()).append("01"); + dataBuff.append("|").append("+0.000000000112"); + + for (int i = 1; i < 16; i++) + { + int valid = validStr.mid(i, 1).toInt(); + int zero = qrand() % 2; + double data = qrand() % 200 * 1e-12; + + dataBuff.append("|"); + if (valid == 0) + { + dataBuff.append("+0.000000000000"); + } else + { + dataBuff.append(zero == 0 ? "+" : "-"); + dataBuff.append(QString::number(data, 'f', 12)); + } + } + + buffer.append(statusBuff).append(dataBuff).append("0"); + + emit dataRecieved(buffer); +// for (int i = 1; i <= 8; i++) +// { +// QByteArray buffer; + +// QString channel = QString("%1").arg(i); +// QString channelRef = "1"; +// QString dataValue = QString("%1").arg(qrand() % 400); +// QString level = QString("%1").arg(qrand() % 4 / (double) 10); +// QString frameId = QString("%1").arg(now.toSecsSinceEpoch() % 10000); + +// buffer.append("$GL,") +// .append("0,").append(channel + ",").append("1,").append(channelRef + ",") +// .append(dataValue + ",").append("1,").append(level + ",").append(frameId + "*") +// .append("00").append("\r\n"); + +// emit dataRecieved(buffer); +// } +} diff --git a/CounterAcqBM/common/utils/QSerialPortUtil.h b/CounterAcqBM/common/utils/QSerialPortUtil.h new file mode 100644 index 0000000..accf403 --- /dev/null +++ b/CounterAcqBM/common/utils/QSerialPortUtil.h @@ -0,0 +1,30 @@ +#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; + + void mockReceivData(); + +signals: + void dataRecieved(QByteArray data); // 收到数据的信号 +}; + +#endif // QSERIALPORTUTIL_H diff --git a/CounterAcqBM/common/utils/SettingConfig.cpp b/CounterAcqBM/common/utils/SettingConfig.cpp new file mode 100644 index 0000000..1f2ebb2 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.cpp @@ -0,0 +1,26 @@ +#include "SettingConfig.h" + +SettingConfig::SettingConfig() +{ + filename = QApplication::applicationDirPath() + "/conf/config.ini"; + setting = new QSettings(this->filename, QSettings::IniFormat); + + BAUD_RATE = getProperty("com", "baudRate").toUInt(); + + NEED_KAFKA = getProperty("kafka", "needKafka").toUInt(); + KAFKA_BROKERS = getProperty("kafka", "brokers").toString(); + KAFKA_DATA_TOPIC = getProperty("kafka", "dataTopic").toString(); + + CLIENT_ID = getProperty("client", "clientId").toString(); + APP_KEY = getProperty("client", "appKey").toString(); + + BASE_URL = getProperty("http", "baseUrl").toString(); + + BASE_LOG_PATH = getProperty("log", "basePath").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/CounterAcqBM/common/utils/SettingConfig.h b/CounterAcqBM/common/utils/SettingConfig.h new file mode 100644 index 0000000..ce1e933 --- /dev/null +++ b/CounterAcqBM/common/utils/SettingConfig.h @@ -0,0 +1,50 @@ +#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); + + /******** 以下为需要的各类参数 ********/ + int BAUD_RATE; + + int NEED_KAFKA; + QString KAFKA_BROKERS; + QString KAFKA_DATA_TOPIC; + + QString CLIENT_ID; + QString APP_KEY; + + QString BASE_URL; + + QString BASE_LOG_PATH; + +private: + SettingConfig(); + + QString filename; + QSettings * setting; +}; + +#endif // SETTINGCONFIG_H diff --git a/CounterAcqBM/conf/config.ini b/CounterAcqBM/conf/config.ini new file mode 100644 index 0000000..da0eacf --- /dev/null +++ b/CounterAcqBM/conf/config.ini @@ -0,0 +1,18 @@ +[com] +baudRate=115200 + +[kafka] +needKafka=0 +brokers="111.198.10.15:12502" +dataTopic="cppTest" + +[client] +clientId="clock" +appKey="bd347bdd20943d2db8af558c3712a357" +devType="BM" + +[http] +baseUrl="http://111.198.10.15:11410" + +[log] +basePath="D://Workspace Qt//ZXSSCJ-Release//Counter//logs//" diff --git a/CounterAcqBM/main.cpp b/CounterAcqBM/main.cpp new file mode 100644 index 0000000..5f0cc86 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/CounterProtocolBM.cpp b/CounterAcqBM/protocol/CounterProtocolBM.cpp new file mode 100644 index 0000000..2aca849 --- /dev/null +++ b/CounterAcqBM/protocol/CounterProtocolBM.cpp @@ -0,0 +1,62 @@ +#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(","); + + 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).toLongLong(); + counterData->load = subList.at(5); + 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/CounterAcqBM/protocol/CounterProtocolBM.h b/CounterAcqBM/protocol/CounterProtocolBM.h new file mode 100644 index 0000000..a6a9180 --- /dev/null +++ b/CounterAcqBM/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/CounterAcqBM/protocol/dto/CounterDataDto.cpp b/CounterAcqBM/protocol/dto/CounterDataDto.cpp new file mode 100644 index 0000000..711911f --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.cpp @@ -0,0 +1,62 @@ +#include "CounterDataDto.h" +#include "common/utils/SettingConfig.h" + +CounterDataDto::CounterDataDto(QObject *parent) : QObject(parent) +{ + +} + +QJsonObject CounterDataDto::toJSON() +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelClockValue * 1E-12)); + dataObj.insert("rawValue", QString("%1").arg(this->channelData)); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", this->channelId); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +QJsonObject CounterDataDto::toJSON(int i) +{ + QJsonObject jsonObj; + + QJsonObject dataObj; + dataObj.insert("channelRefNo", this->channelRefId); + dataObj.insert("dataValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("rawValue", QString("%1").arg(this->channelDataArray.at(i))); + dataObj.insert("frameId", this->frameId); + + jsonObj.insert("channelNo", (i + 1)); + jsonObj.insert("ts", this->milisecond); + jsonObj.insert("data", dataObj); + + return jsonObj; +} + +void CounterDataDto::clone(CounterDataDto *copy) +{ + copy->frameId = this->frameId; + copy->level = this->level; + copy->load = this->load; + copy->channelData = this->channelData; + copy->channelRefId = this->channelRefId; + copy->channelActive = this->channelActive; + copy->channelId = channelId; + copy->type = 0; + + copy->channelClockValue = this->channelClockValue; + + copy->rawFrame = this->rawFrame; + + copy->timestamp = this->timestamp; + copy->milisecond = this->milisecond; + copy->devCode = this->devCode; + copy->devStatus = this->devStatus; +} diff --git a/CounterAcqBM/protocol/dto/CounterDataDto.h b/CounterAcqBM/protocol/dto/CounterDataDto.h new file mode 100644 index 0000000..ff19375 --- /dev/null +++ b/CounterAcqBM/protocol/dto/CounterDataDto.h @@ -0,0 +1,43 @@ +#ifndef COUNTERDATADTO_H +#define COUNTERDATADTO_H + +#include +#include +#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> + qlonglong channelData; // 通道测量数据,单位:10ps -- <5> + qint8 channelRefId; // 参考通道号 -- <4> + qint8 channelActive; // 通道有效标志 -- <3> + qint8 channelId; // 测量通道号 -- <2> + qint8 type = 0; // 测量状态 -- <1> + + double channelClockValue; // + + QList channelActiveArray; // xhts + QList channelDataArray; // xhts + + QByteArray rawFrame; // 原始帧字节数组 + + QString timestamp; // 时间戳字符串 + qlonglong milisecond; // 毫秒计数 + QString devCode; + QString devStatus; + + QJsonObject toJSON(); + QJsonObject toJSON(int i); + void clone(CounterDataDto * copy); + +signals: + +}; + +#endif // COUNTERDATADTO_H diff --git a/CounterAcqBM/protocol/protocol.pri b/CounterAcqBM/protocol/protocol.pri new file mode 100644 index 0000000..ef4b391 --- /dev/null +++ b/CounterAcqBM/protocol/protocol.pri @@ -0,0 +1,8 @@ + +SOURCES += $$PWD/CounterProtocolBM.cpp +#SOURCES += $$PWD/CounterProtocolXH.cpp +SOURCES += $$PWD/dto/CounterDataDto.cpp + +HEADERS += $$PWD/CounterProtocolBM.h +#HEADERS += $$PWD/CounterProtocolXH.h +HEADERS += $$PWD/dto/CounterDataDto.h diff --git a/ZXSSCJ.pro b/ZXSSCJ.pro index 9c26cb8..bda58e2 100644 --- a/ZXSSCJ.pro +++ b/ZXSSCJ.pro @@ -4,7 +4,8 @@ #CONFIG += ordered SUBDIRS += CounterAcq #计数器数据采集 +SUBDIRS += CounterAcqBM #6906计数器数据采集 SUBDIRS += PhaseCompAcq #比相仪数据采集 #SUBDIRS += DevStatusAcq -SUBDIRS += DeviceHub # -#SUBDIRS += HClockAcq #氢钟状态数据采集 +SUBDIRS += DeviceHub # +#SUBDIRS += HClockAcq #氢钟状态数据采集