360 lines
11 KiB
C++
360 lines
11 KiB
C++
|
#include "mainwindow.h"
|
|||
|
#include "ui_mainwindow.h"
|
|||
|
|
|||
|
#include <QtCore/QCoreApplication>
|
|||
|
#include <QVector>
|
|||
|
#include <QThread>
|
|||
|
#include <QDebug>
|
|||
|
|
|||
|
#include "libmodbus/modbus.h"
|
|||
|
|
|||
|
#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();
|
|||
|
InitializeModbus();
|
|||
|
}
|
|||
|
|
|||
|
MainWindow::~MainWindow()
|
|||
|
{
|
|||
|
delete ui;
|
|||
|
|
|||
|
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();
|
|||
|
}
|
|||
|
|
|||
|
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()
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
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)
|
|||
|
{
|
|||
|
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;
|
|||
|
|
|||
|
DeviceData* pDevice = nullptr;
|
|||
|
|
|||
|
if (pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_00_09
|
|||
|
|| pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_09_06)
|
|||
|
pDevice = new TemperatureData();
|
|||
|
|
|||
|
startAsyncProcess(registers,pItem->id,pItem->start_address, pItem->quantity, pDevice);
|
|||
|
|
|||
|
if (pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_00_09
|
|||
|
|| pItem->start_address == TH08D_TEMPERATURE_EQUIPMENT_81_09_06)
|
|||
|
{
|
|||
|
TemperatureData* pData = (TemperatureData*)pDevice;
|
|||
|
assert(pData);
|
|||
|
if (pData->bDecodeTemp)
|
|||
|
{
|
|||
|
ui->txt_content_1->append(QString(tr("温度:%1\n湿度: %2\n露点: %3\n")).arg(pData->TempValue).arg(pData->HumidityValue).arg(pData->DewPointValue));
|
|||
|
}
|
|||
|
if (pData->bDecodeAlarm)
|
|||
|
{
|
|||
|
ui->txt_content_1->append(QString(tr("高温告警:%1\n低温告警: %2\n湿度告警: %3\n")).arg(pData->TempHighAlarm).arg(pData->TempLowAlarm).arg(pData->HumidityHighAlarm));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
qDebug() << "同步读取地址" << pItem->start_address;
|
|||
|
}
|
|||
|
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);
|
|||
|
|
|||
|
// 工作完成后退出线程
|
|||
|
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();
|
|||
|
|
|||
|
QEventLoop loop;
|
|||
|
QObject::connect(worker, &DecodeWorker::finished, &loop, &QEventLoop::quit);
|
|||
|
|
|||
|
// 发射信号传递参数
|
|||
|
emit startProcessing(array, slave_id, start_addr, quantity, pDevice);
|
|||
|
|
|||
|
// 阻塞,等待线程结束
|
|||
|
loop.exec();
|
|||
|
|
|||
|
qDebug() << "同步读取完成";
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void MainWindow::on_btn_read_register_clicked()
|
|||
|
{
|
|||
|
readRegister(0,0,0);
|
|||
|
}
|
|||
|
|