emsApplication/applications/EmsShower/mainwindow.cpp

519 lines
17 KiB
C++
Raw Normal View History

2025-03-04 11:27:16 +08:00
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCore/QCoreApplication>
#include <QVector>
#include <QThread>
#include <QDebug>
2025-03-04 17:19:03 +08:00
#include <QGridLayout>
#include <QToolBar>
#include <QLabel>
#include <QGraphicsDropShadowEffect>
2025-03-05 13:37:23 +08:00
#include <QMessageBox>
#include <QSizePolicy>
#include <QFontDatabase>
2025-03-04 11:27:16 +08:00
#include "libmodbus/modbus.h"
2025-03-05 13:37:23 +08:00
#include "customwidget.h"
#include "formserialportsettingdialog.h"
2025-03-04 11:27:16 +08:00
#define _DEBUG_VSPD_
#define TH08D_TEMPERATURE_EQUIPMENT_81_00_09 40000
#define TH08D_TEMPERATURE_EQUIPMENT_81_09_06 40009
// 处理数组的槽函数
void DecodeWorker::processArray(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData)
{
switch (start_addr)
{
case TH08D_TEMPERATURE_EQUIPMENT_81_00_09:
{
assert(pData->m_device_type == 81);
TemperatureData* pTemperature = (TemperatureData*)pData;
uint16_t value;
int index = 0;
pTemperature->m_device_online_state = array[index++]; //设备通讯状态
pTemperature->TempValue = (float)array[index++] * 1.0f / 10.f; //温度
pTemperature->HumidityValue = (float)array[index++] * 1.0f / 10.f; //湿度
pTemperature->DewPointValue = (float)array[index++] * 1.0f; //露点
value = array[index++]; //跳过温度偏移量
value = array[index++]; //跳过湿度偏移量
pTemperature->DO= array[index++]; //DO
pTemperature->DI1 = array[index++]; //DI1
pTemperature->DI2 = array[index++]; //DI2
pTemperature->bDecodeAlarm = false;
pTemperature->bDecodeTemp = true;
}
break;
case TH08D_TEMPERATURE_EQUIPMENT_81_09_06:
{
assert(pData->m_device_type == 81);
TemperatureData* pTemperature = (TemperatureData*)pData;
pTemperature->bDecodeAlarm = true;
pTemperature->bDecodeTemp = false;
uint16_t value;
int index = 0;
float temp_threshold = (float)array[index++] * 1.0f / 10.f; //温度阈值
float temp_offset = (float)array[index++] * 1.0f / 10.f; //温控偏移量
value = array[index++]; //跳过设备状态
pTemperature->TempHighAlarm = array[index++]; //高温告警
pTemperature->HumidityHighAlarm = array[index++]; //高湿度告警
pTemperature->TempLowAlarm = array[index++]; //低温告警
}
break;
default:
break;
}
//下面是模拟发送进度
//for (int i = 0; i < array.size(); ++i)
//{
// qDebug() << "Worker处理索引:" << i << "值:" << array[i]
// << "线程:" << QThread::currentThread();
// //QThread::msleep(100); // 模拟耗时处理
// emit progress(i);
//}
qDebug() << "Worker thread finished";
emit finished();
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
,m_pModbus(nullptr)
,m_pSettings(nullptr)
{
ui->setupUi(this);
m_version= "1.0.0";
m_modbus_type = 1;
m_modbus_ip = "127.0.0.1";
m_modbus_port = 502;
m_modbus_com = "COM1";
m_modbus_baund = 9600;
m_modbus_data = 1;
m_modbus_parity = 0;
m_modbus_stop = 1;
m_modbus_slave_id = 1;
InitializeUI();
}
MainWindow::~MainWindow()
{
if (m_pModbus)
{
modbus_close(m_pModbus);
modbus_free(m_pModbus);
m_pModbus = nullptr;
}
for (SlaveItem* ptr : m_SlaveData)
{
delete ptr;
ptr = nullptr;
}
m_SlaveData.clear();
2025-03-04 14:22:27 +08:00
if (m_pSettings!=nullptr)
{
delete m_pSettings;
m_pSettings = nullptr;
}
2025-03-05 13:37:23 +08:00
delete ui;
2025-03-04 11:27:16 +08:00
}
void MainWindow::getConfiguration(QString iniFilePath)
{
m_pSettings = new QSettings(iniFilePath, QSettings::IniFormat);
m_version = m_pSettings->value("version/ver").toString();
m_modbus_type = m_pSettings->value("modbus/type").toInt();
m_modbus_ip = m_pSettings->value("modbus/ip").toString();
m_modbus_port = m_pSettings->value("modbus/port").toInt();
m_modbus_com = m_pSettings->value("modbus/com").toString();
m_modbus_baund = m_pSettings->value("modbus/baund").toInt();
m_modbus_data = m_pSettings->value("modbus/data").toInt();
m_modbus_parity = m_pSettings->value("modbus/parity").toInt();
m_modbus_stop = m_pSettings->value("modbus/stop").toInt();
m_modbus_slave_id = m_pSettings->value("slaves/slave_id").toInt();
QString app = QString("slave_%1/function_code_counts").arg(m_modbus_slave_id);
int functions_count = m_pSettings->value(app).toInt();
for(int i=0; i<functions_count; i++)
{
QString app2 = QString("slave_%1_function_%2").arg(m_modbus_slave_id).arg(i);
#ifndef _DEBUG_VSPD_
unsigned short equipmentCode = m_pSettings->value(app2 + "/equipment_code").toInt();
equipmentCode = equipmentCode << 9;
equipmentCode &= 0xFE00; // 二进制掩码: 1111 1110 0000 0000保留高7位
QStringList sn_list = m_pSettings->value(app2 + "/serial_number").toString().split(":", Qt::SkipEmptyParts);
QStringList quantity_list = m_pSettings->value(app2 + "/read_quantity").toString().split(":", Qt::SkipEmptyParts);
assert(sn_list.size() == quantity_list.size());
int j = 0;
foreach(const QString sn, sn_list)
{
SlaveItem* pSlaveData = new SlaveItem();
pSlaveData->id = m_modbus_slave_id;
pSlaveData->function_code = m_pSettings->value(app2 + "/function_code").toInt();
pSlaveData->interval = m_pSettings->value(app2 + "/interval").toInt();
unsigned short serialNumber = sn.toInt();
serialNumber &= 0x01FF; // 二进制掩码: 0000 0001 1111 1111保留低9位
// 组合操作高7位左移9位低9位直接填充
unsigned short address = pSlaveData->start_address = (equipmentCode ) | serialNumber; // 关键位操作
pSlaveData->start_address = address;
pSlaveData->quantity = quantity_list.at(j).toInt();
m_SlaveData.push_back(pSlaveData);
j++;
}
#else
SlaveItem* pSlaveData = new SlaveItem();
pSlaveData->id = m_modbus_slave_id;
pSlaveData->function_code = m_pSettings->value(app2 + "/function_code").toInt();
pSlaveData->interval = m_pSettings->value(app2 + "/interval").toInt();
pSlaveData->quantity = m_pSettings->value(app2 + "/quantity").toInt();
pSlaveData->start_address = m_pSettings->value(app2 + "/start_addr").toInt();
m_SlaveData.push_back(pSlaveData);
#endif
}
}
bool MainWindow::InitializeUI()
{
2025-03-05 13:37:23 +08:00
#ifndef NDEBUG
this->showMaximized();
#endif
2025-03-04 17:19:03 +08:00
//初始化窗口边框
2025-03-05 13:37:23 +08:00
QWidget *centralWidget = this->centralWidget(); // new QWidget(this);
QGridLayout *mainLayout = new QGridLayout(centralWidget);
this->setStyleSheet("background-color: white;");
//this->setProperty("canMove",true);
//设置窗体透明
2025-03-04 17:19:03 +08:00
this->setAttribute(Qt::WA_TranslucentBackground, true);
2025-03-05 13:37:23 +08:00
//设置无边框
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
//实例阴影shadow
2025-03-04 17:19:03 +08:00
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
2025-03-05 13:37:23 +08:00
//设置阴影距离
2025-03-04 17:19:03 +08:00
shadow->setOffset(0, 0);
2025-03-05 13:37:23 +08:00
//设置阴影颜色
shadow->setColor(QColor(44,44,44));
//设置阴影圆角
2025-03-04 17:19:03 +08:00
shadow->setBlurRadius(16);
2025-03-05 13:37:23 +08:00
//给嵌套QDialog设置阴影
ui->centralwidget->setGraphicsEffect(shadow);
//给垂直布局器设置边距(此步很重要, 设置宽度为阴影的宽度)
//->setMargin(12);
2025-03-04 17:19:03 +08:00
// 创建2行4列布局共8个控件示例
for(int row=0; row<2; ++row)
{
for(int col=0; col<4; ++col)
{
2025-03-05 13:37:23 +08:00
#if 0
2025-03-04 17:19:03 +08:00
QLabel *label = new QLabel(QString("Cell %1-%2").arg(row).arg(col),this);
2025-03-05 13:37:23 +08:00
label->setStyleSheet("background-color: rgb(192,192,192);"
2025-03-04 17:19:03 +08:00
"color: #333333;"
"border-radius: 8px;"
"font: bold 14px;");
label->setAutoFillBackground(true);
label->setAlignment(Qt::AlignCenter);
label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
mainLayout->addWidget(label, row, col);
m_panel_labels.push_back(label);
2025-03-05 13:37:23 +08:00
#endif
CustomWidget* pWidget = new CustomWidget(this);
mainLayout->addWidget(pWidget, row, col);
2025-03-04 17:19:03 +08:00
}
}
// 设置布局的间距和边距
mainLayout->setSpacing(5);
//mainLayout->setContentsMargins(10, 40, 10, 10); // 顶部留出工具栏空间
2025-03-05 13:37:23 +08:00
//setCentralWidget(centralWidget);
2025-03-04 17:19:03 +08:00
QToolBar *toolBar = new QToolBar(this);
toolBar->setMovable(false);
2025-03-05 13:37:23 +08:00
toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
2025-03-04 17:19:03 +08:00
toolBar->setIconSize(QSize(64,64));
2025-03-05 13:37:23 +08:00
// 设置按钮悬停效果(通过样式表)
// toolBar->setStyleSheet(
// "QToolButton { background: transparent; border: none; }"
// "QToolButton:hover { background: #e0e0e0; border-radius: 4px; }"
// );
2025-03-04 17:19:03 +08:00
// 添加工具栏按钮
QAction *actionRead = new QAction(QIcon(":/icons/modular.png"), tr("Read"), this);
actionRead->setToolTip(tr("Read Data"));
2025-03-05 13:37:23 +08:00
QAction *actionSetting = new QAction(QIcon(":/icons/setting.png"), tr("Setting"), this);
actionSetting->setToolTip(tr("Setting Modbud Port"));
2025-03-04 17:19:03 +08:00
QAction *actionClose = new QAction(QIcon(":/icons/close.png"), tr("Close"), this);
actionClose->setToolTip(tr("Close Application"));
2025-03-05 13:37:23 +08:00
//添加按钮
2025-03-04 17:19:03 +08:00
toolBar->addAction(actionRead);
toolBar->addSeparator();
2025-03-05 13:37:23 +08:00
// 添加间隔控件
QWidget *spacer = new QWidget();
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolBar->addWidget(spacer);
// 添加中央标签
QLabel *label = new QLabel(tr("综合电源柜监测"), this);
// 加载字体
int fontId = QFontDatabase::addApplicationFont(":/fonts/Alimama_DongFangDaKai_Regular.ttf");
if (fontId == -1)
{
qDebug() << "字体加载失败";
return -1;
}
//QFont customFont("Alimama DongFangDaKai", 48);
//customFont.setBold(true);
//label->setFont(customFont);
//label->setStyleSheet("color: #2E86C1;");
label->setStyleSheet(
"QLabel {"
" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
" font-size: 52px;"
" color: #2E86C1;"
//" font-weight: bold;"
"}"
);
toolBar->addWidget(label);
QWidget *spacerWidget = new QWidget();
spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolBar->addWidget(spacerWidget);
toolBar->addAction(actionSetting);
2025-03-04 17:19:03 +08:00
toolBar->addSeparator();
2025-03-05 13:37:23 +08:00
toolBar->addAction(actionClose);
// 将工具栏定位到窗口顶部·
2025-03-04 17:19:03 +08:00
addToolBar(Qt::TopToolBarArea, toolBar);
connect(actionClose, &QAction::triggered, this, &QMainWindow::close);
2025-03-05 13:37:23 +08:00
connect(actionSetting, &QAction::triggered, this, &MainWindow::SettingSerialPort);
2025-03-04 17:19:03 +08:00
connect(actionRead, &QAction::triggered, this, &MainWindow::ReadSerialPortData);
2025-03-05 13:37:23 +08:00
ui->statusbar->showMessage(tr("Ready"), 0);
return true;
2025-03-04 11:27:16 +08:00
}
bool MainWindow::InitializeModbus()
{
QString appDir = QCoreApplication::applicationDirPath();
QString iniFilePath = appDir + QString::fromStdString("/emsshower.ini");
getConfiguration(iniFilePath);
switch (m_modbus_type)
{
case 0:
return InitializeTcp();
break;
default:
case 1:
return InitializeRtu();
break;
}
}
bool MainWindow::InitializeRtu()
{
if(m_pModbus)
{
modbus_close(m_pModbus);
m_pModbus = nullptr;
}
std::string com = std::string("\\\\.\\") + m_modbus_com.toStdString();
m_pModbus = modbus_new_rtu(com.c_str(), m_modbus_baund, 'N', m_modbus_data, m_modbus_stop);
int slave_id = m_modbus_slave_id;
//modbus_set_debug(m_pModbus, true);
modbus_set_slave(m_pModbus, slave_id); //设置modbus从机地址
modbus_rtu_set_serial_mode(m_pModbus, MODBUS_RTU_RS485);
int rc = modbus_connect(m_pModbus);
if (rc == -1)
return false;
struct timeval t;
t.tv_sec=0;
t.tv_usec=1000000; //设置modbus超时时间为1000毫秒
modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec);
return true;
}
bool MainWindow::InitializeTcp()
{
if(m_pModbus)
{
modbus_close(m_pModbus);
m_pModbus = nullptr;
}
std::string ip = m_modbus_ip.toStdString();
int port = m_modbus_port;
m_pModbus = modbus_new_tcp(ip.c_str(), port); //由于是tcp client连接在同一个程序中相同的端口可以连接多次。
if (m_pModbus == nullptr)
{
return false;
}
int slave_id = m_modbus_slave_id;
modbus_set_slave(m_pModbus, slave_id); //从机地址
int rc = modbus_connect(m_pModbus);
if (rc == -1)
return false;
struct timeval t;
t.tv_sec=0;
t.tv_usec=1000000; //设置modbus超时时间为1000毫秒
modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec);
return true;
}
bool MainWindow::readRegister(int addr,int nb,uint16_t* dest)
{
2025-03-05 13:37:23 +08:00
InitializeModbus();
2025-03-04 11:27:16 +08:00
for (auto it = m_SlaveData.begin(); it != m_SlaveData.end(); ++it)
{
SlaveItem* pItem = (SlaveItem*)(*it);
uint16_t* tab_reg = new uint16_t[pItem->quantity];
int regs = modbus_read_registers(m_pModbus, pItem->start_address, pItem->quantity, tab_reg);
QVector<uint16_t> registers;
for (int i = 0; i < regs; ++i)
{
registers.push_back(tab_reg[i]);
}
delete []tab_reg;
2025-03-04 14:22:27 +08:00
DeviceData* pDevice = nullptr;
2025-03-04 11:27:16 +08:00
2025-03-04 14:22:27 +08:00
if (pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_00_09
|| pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_09_06)
pDevice = new TemperatureData();
2025-03-04 11:27:16 +08:00
startAsyncProcess(registers,pItem->id,pItem->start_address, pItem->quantity, pDevice);
if (pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_00_09
2025-03-04 14:22:27 +08:00
|| pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_09_06)
2025-03-04 11:27:16 +08:00
{
TemperatureData* pData = (TemperatureData*)pDevice;
assert(pData);
2025-03-05 13:37:23 +08:00
QString value;
2025-03-04 11:27:16 +08:00
if (pData->bDecodeTemp)
{
2025-03-04 17:19:03 +08:00
//ui->txt_content_1->append(QString(tr("温度:%1\n湿度: %2\n露点: %3\n")).arg(pData->TempValue).arg(pData->HumidityValue).arg(pData->DewPointValue));
2025-03-05 13:37:23 +08:00
//m_panel_labels[0]->setText(QString(tr("温度: %1\n湿度: %2\n露点: %3\n")).arg(pData->TempValue).arg(pData->HumidityValue).arg(pData->DewPointValue));
2025-03-04 11:27:16 +08:00
}
if (pData->bDecodeAlarm)
{
2025-03-04 17:19:03 +08:00
//ui->txt_content_1->append(QString(tr("高温告警: %1\n低温告警: %2\n湿度告警: %3\n")).arg(pData->TempHighAlarm).arg(pData->TempLowAlarm).arg(pData->HumidityHighAlarm));
//m_panel_labels[0]->setText(QString(tr("高温告警: %1\n低温告警: %2\n湿度告警: %3\n")).arg(pData->TempHighAlarm).arg(pData->TempLowAlarm).arg(pData->HumidityHighAlarm));
2025-03-04 11:27:16 +08:00
}
}
qDebug() << "同步读取地址" << pItem->start_address;
2025-03-04 14:22:27 +08:00
delete pDevice;
2025-03-04 11:27:16 +08:00
}
return true;
}
void MainWindow::startAsyncProcess(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity, DeviceData* pDevice)
{
QThread* thread = new QThread;
DecodeWorker* worker = new DecodeWorker;
worker->moveToThread(thread);
worker->setParameters(array, slave_id, start_addr, quantity, pDevice);
// 连接线程启动信号和槽函数
connect(this, &MainWindow::startProcessing, worker, &DecodeWorker::processArray);
2025-03-04 14:22:27 +08:00
2025-03-04 11:27:16 +08:00
// 工作完成后退出线程
connect(worker, &DecodeWorker::finished, thread, &QThread::quit);
connect(worker, &DecodeWorker::finished, worker, &DecodeWorker::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
//// 可选连接进度信号更新UI
//connect(worker, &DecodeWorker::progress, this, [](int index)
//{
// qDebug() << "进度更新,当前处理到索引:" << index;
//});
thread->start();
2025-03-04 14:22:27 +08:00
QEventLoop loop;
QObject::connect(worker, &DecodeWorker::finished, &loop, &QEventLoop::quit);
2025-03-04 11:27:16 +08:00
2025-03-04 14:22:27 +08:00
// 发射信号传递参数
emit startProcessing(array, slave_id, start_addr, quantity, pDevice);
2025-03-04 11:27:16 +08:00
2025-03-04 14:22:27 +08:00
// 阻塞,等待线程结束
2025-03-04 11:27:16 +08:00
loop.exec();
qDebug() << "同步读取完成";
}
2025-03-04 17:19:03 +08:00
void MainWindow::ReadSerialPortData()
2025-03-04 11:27:16 +08:00
{
readRegister(0,0,0);
}
2025-03-05 13:37:23 +08:00
void MainWindow::SettingSerialPort()
{
FormSerialPortSettingDialog* dlg = new FormSerialPortSettingDialog(this);
dlg->setWindowFlags(dlg->windowFlags()&~(Qt::WindowMinMaxButtonsHint|Qt::WindowContextHelpButtonHint));
//dlg.setModal(true);
//dlg->show();
if(dlg->exec() == QDialog::Accepted)
QMessageBox::information(this, "OK Clicked", "Button 1 was clicked!");
else
QMessageBox::information(this, "Cancel Clicked", "Cancel was clicked!");
}