更新为通过json文件定义解码,详细配置见json文件

main
HwangKC 2025-03-16 14:20:19 +08:00
parent 63b9f7d141
commit 33ab44bd08
6 changed files with 657 additions and 63 deletions

View File

@ -67,7 +67,7 @@ void CustomDisplayPanel::Build()
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
" font-family: 'Arial';"
" font-size: 20px;"
" color: #13396E;"
" color: #20549E;"
" font-weight: bold;"
" font-style: black;"
"}"
@ -139,6 +139,8 @@ void CustomDisplayPanel::Build()
tableWidget->setShowGrid(true); // 默认显示网格线[3](@ref)
tableWidget->setStyleSheet("QTableWidget { gridline-color: #e0e0e0; background-color: white; border-radius: 10px;}");
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
// **应用阴影效果**
QGraphicsDropShadowEffect *shadowTable = new QGraphicsDropShadowEffect(this);
shadowTable->setBlurRadius(10);
@ -169,7 +171,7 @@ void CustomDisplayPanel::UpdateData(OpenJson& json)
void CustomDisplayPanel::UpdateTemperature(OpenJson &json)
{
auto& nodeLabel = json["text_panel"];
qDebug() << nodeLabel.size();
qDebug() << "text_panel: " << nodeLabel.size();
for(size_t i=0; i<nodeLabel.size(); i++)
{
auto& node = nodeLabel[i];
@ -180,10 +182,32 @@ void CustomDisplayPanel::UpdateTemperature(OpenJson &json)
if (i == 0)
{
if (value == "1")
{
disp = QString("Online");
m_txtLabels[i]->setStyleSheet(
"QLabel {"
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
" font-family: 'Arial';"
" font-size: 20px;"
" color: #2E86C1;"
" font-weight: bold;"
"}"
);
}
else
{
disp = QString("Offline");
m_txtLabels[i]->setStyleSheet(
"QLabel {"
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
" font-family: 'Arial';"
" font-size: 20px;"
" color: #FF0000;"
" font-weight: bold;"
" font-style: black"
"}"
);
}
}
else
{
@ -193,7 +217,7 @@ void CustomDisplayPanel::UpdateTemperature(OpenJson &json)
}
auto& nodeTable = json["table"];
qDebug() << nodeTable.size();
qDebug() << "table: "<< nodeTable.size();
m_pTableWidget->clear();
m_pTableWidget->setRowCount(nodeTable.size());
@ -255,6 +279,8 @@ void CustomDisplayPanel::UpdateAlarm(OpenJson &json)
auto& nodeTable = json["alarm"];
qDebug() << nodeTable.size();
m_pTableWidget->setUpdatesEnabled(false);
for(size_t i=0; i<nodeTable.size(); i++)
{
m_pTableWidget->insertRow(0);
@ -280,6 +306,22 @@ void CustomDisplayPanel::UpdateAlarm(OpenJson &json)
m_pTableWidget->setItem(0, 1, item1);
m_pTableWidget->setItem(0, 2, item2);
}
m_pTableWidget->setUpdatesEnabled(true);
// 自动定位到首行
if(m_pTableWidget->rowCount() > 0)
{
// 创建首行索引
QModelIndex firstIndex = m_pTableWidget->model()->index(0, 0);
// 滚动到首行并置顶
m_pTableWidget->scrollTo(firstIndex, QAbstractItemView::PositionAtTop);
// 选中整行(需提前设置选择模式)
m_pTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pTableWidget->setCurrentIndex(firstIndex);
}
}
////////

View File

@ -1,67 +1,36 @@
;通用设置
[version]
ver="1_0_0"
ver=1_0_0
[modbus]
;1=RTU 0=TCP
type=1
;if type=1, ignore ip and port setting
ip="127.0.0.1"
ip=127.0.0.1
port=502
com="COM20"
com=COM20
baund=9600
data=8
;0=None 1=Odd 2=Even
parity=0
stop=1
[slaves]
;如果从机数量多于1则从机地址slave_id以:分隔(英文冒号)
slave_id="1"
;每一个从机的配置
;由两个节组成slave_%d 和 slave_%d_function_%d
slave_id=1
[slave_1]
;支持的功能码数量
function_code_counts=2
[slave_1_function_0]
;功能码
function_code=3
;起始地址10进制
start_addr=40000
;读取数量
quantity=9
;扫描间隔,单位ms
interval=1000
;serial_number与read_quantity的元素数量要一样
equipment_code=81
serial_number="0:1:2:3:4:5:6:7:8:9:10:11:12:13:14"
read_quantity="1:1:1:1:1:1:1:1:1:1:1:1:1:1:1"
serial_number=0:1:2:3:4:5:6:7:8:9:10:11:12:13:14
read_quantity=1:1:1:1:1:1:1:1:1:1:1:1:1:1:1
[slave_1_function_1]
;功能码
function_code=3
;起始地址10进制
start_addr=40009
;读取数量
quantity=6
;扫描间隔,单位ms
interval=1000
;serial_number与read_quantity的元素数量要一样
equipment_code=81
serial_number="0:1:2:3:4:5:6:7:8:9:10:11:12:13:14"
read_quantity="1:1:1:1:1:1:1:1:1:1:1:1:1:1:1"
serial_number=0:1:2:3:4:5:6:7:8:9:10:11:12:13:14
read_quantity=1:1:1:1:1:1:1:1:1:1:1:1:1:1:1

View File

@ -0,0 +1,191 @@
{
"modbus":
{
"type":"rs485",
"port":"COM1",
"baudrate":9600,
"parity":"N",
"stopbits":1,
"data":8,
"ip":"127.0.0.1",
"ip_port":502
},
"slaves":[
{
"id":1,
"function_code":3,
"address":[
{
"start_addr":40000,
"quantity":9,
"bytes_per_register":2,
"device_name_chn":"温湿度",
"device_name_eng":"Temperature",
"device_type":1,
"data": [
{
"comment":"在线状态",
"order":0,
"precision":1,
"unit":"",
"title_chn":"在线状态",
"title_eng":"Online",
"display":1,
"skip":0
},
{
"comment":"温度",
"order":1,
"precision":10,
"unit":"℃",
"title_chn":"温度",
"title_eng":"T (℃) ",
"display":1,
"skip":0
},
{
"comment":"湿度",
"order":2,
"precision":10,
"unit":"%",
"title_chn":"湿度",
"title_eng":"RH (%)",
"display":1 ,
"skip":0
},
{
"comment":"露点",
"order":3,
"precision":1,
"unit":"",
"title_chn":"露点",
"title_eng":"DewPoint",
"display":2,
"skip":0
},
{
"comment":"跳过",
"order":4,
"precision":1,
"unit":"",
"title_chn":"",
"title_eng":"",
"display":0,
"skip":1
},
{
"comment":"跳过",
"order":5,
"precision":1,
"unit":"",
"title_chn":"",
"title_eng":"",
"display":0,
"skip":1
},
{
"comment":"DO",
"order":6,
"precision":1,
"unit":"",
"title_chn":"DO",
"title_eng":"DO",
"display":2,
"skip":0
},
{
"comment":"DI1",
"order":7,
"precision":1,
"unit":"",
"title_chn":"DI1",
"title_eng":"DI1",
"display":2,
"skip":0
},
{
"comment":"DI2",
"order":8,
"precision":1,
"unit":"",
"title_chn":"DI2",
"title_eng":"DI2",
"display":2,
"skip":0
}
]
},
{
"start_addr":40009,
"quantity":6,
"bytes_per_register":2,
"device_name_chn":"温湿度告警",
"device_name_eng":"Alarm",
"device_type":6,
"data": [
{
"comment":"温度阈值",
"order":0,
"precision":10,
"unit":"",
"title_chn":"温度阈值",
"title_eng":"Temp_threshold",
"display":0,
"skip":0
},
{
"comment":"温度偏移",
"order":1,
"precision":1,
"unit":"",
"title_chn":"温度偏移",
"title_eng":"Temp_offset",
"display":0,
"skip":0
},
{
"comment":"跳过",
"order":2,
"precision":1,
"unit":"",
"title_chn":"",
"title_eng":"",
"display":0,
"skip":1
},
{
"comment":"高温告警",
"order":3,
"precision":1,
"unit":"",
"title_chn":"高温告警",
"title_eng":"High Temp.",
"display":1,
"skip":0
},
{
"comment":"高湿告警",
"order":4,
"precision":1,
"unit":"",
"title_chn":"高湿告警",
"title_eng":"High Humidity",
"display":1,
"skip":0
},
{
"comment":"低温告警",
"order":5,
"precision":1,
"unit":"",
"title_chn":"低温告警",
"title_eng":"Low Temp.",
"display":0,
"skip":0
}
]
}
]
}
]
}

View File

@ -25,6 +25,10 @@
#define TH08D_TEMPERATURE_EQUIPMENT_81_00_09 40000
#define TH08D_TEMPERATURE_EQUIPMENT_81_09_06 40009
void DecodeWorker::setSlaveAddress(const slaveAddress& sa)
{
m_slaveAddress = sa;
}
// 处理数组的槽函数
void DecodeWorker::processArray(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData)
{
@ -88,6 +92,31 @@ void DecodeWorker::processArray(const QVector<uint16_t>& array,int slave_id,int
emit finished();
}
void DecodeWorker::processRegisterData(const QVector<uint16_t> &array, const slaveAddress& sa, DeviceData *pData)
{
GeneralDeviceData* pGeneralData = (GeneralDeviceData*)pData;
RegisterDataItems::const_iterator iter = sa.register_data_items.begin();
int idx = 0;
for(; iter!=sa.register_data_items.end(); iter++)
{
if (iter->second.skip ==0)
{
DisplayDataItem ddi;
ddi.device_type = sa.device_type;
ddi.display_location = iter->second.display;
ddi.order = iter->second.order;
ddi.precision = iter->second.precision;
ddi.title = iter->second.title_chn;
ddi.unit = iter->second.unit;
ddi.value = array[idx];
pGeneralData->m_PanelDisplayDataItems.emplace_back(ddi);
}
idx++;
}
return;
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
@ -153,6 +182,7 @@ void MainWindow::getConfiguration(QString iniFilePath)
m_modbus_parity = m_pSettings->value("modbus/parity").toInt();
m_modbus_stop = m_pSettings->value("modbus/stop").toInt();
#if 0
m_modbus_slave_id = m_pSettings->value("slaves/slave_id").toInt();
QString app = QString("slave_%1/function_code_counts").arg(m_modbus_slave_id);
@ -202,6 +232,61 @@ void MainWindow::getConfiguration(QString iniFilePath)
m_SlaveData.push_back(pSlaveData);
#endif
}
#endif
}
void MainWindow::ReadConfiguration(QString jsonFilePath)
{
OpenJson json;
json.decodeFile(jsonFilePath.toStdString());
auto& nodeSlaves = json["slaves"];
qDebug() << nodeSlaves.size();
for (size_t i = 0; i < nodeSlaves.size(); i++)
{
auto& node = nodeSlaves[i];
slaveItem slave_item;
slave_item.slave_id = node["id"].i32();
slave_item.function_code = node["function_code"].i32();
auto& nodeAddress = node["address"];
for (size_t j = 0; j < nodeAddress.size(); j++)
{
auto& nodeAddrItem = nodeAddress[j];
slaveAddress address_item;
address_item.start_addr = nodeAddrItem["start_addr"].i32();
address_item.quantity = nodeAddrItem["quantity"].i32();
address_item.bytes_per_register = nodeAddrItem["bytes_per_register"].i32();
address_item.device_name_chn = nodeAddrItem["device_name_chn"].s();
address_item.device_name_eng = nodeAddrItem["device_name_eng"].s();
address_item.device_type = nodeAddrItem["device_type"].i32();
auto& nodeData = nodeAddrItem["data"];
for (size_t k = 0; k < nodeData.size(); k++)
{
auto& nodeRegister = nodeData[k];
registryData rdata;
rdata.comment = nodeRegister["comment"].s();
rdata.order = nodeRegister["order"].i32();
rdata.precision = (float)nodeRegister["precision"].d();
rdata.unit = nodeRegister["unit"].s();
rdata.title_chn = nodeRegister["title_chn"].s();
rdata.title_en = nodeRegister["title_eng"].s();
rdata.display = nodeRegister["display"].i32();
rdata.skip = nodeRegister["skip"].i32();
address_item.register_data_items.insert(std::make_pair(rdata.order,rdata));
}
slave_item.slave_address_items.emplace_back(address_item);
}
m_total_slave_items.emplace_back(slave_item);
}
}
bool MainWindow::InitializeUI()
@ -249,10 +334,12 @@ bool MainWindow::InitializeUI()
m_pTemperaturePanel->Build();
mainLayout->addWidget(m_pTemperaturePanel, 0, 0);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_TEMPERATURE,m_pTemperaturePanel));
//电源
m_pPowerPanel = new CustomDisplayPanel(this);
m_pPowerPanel->setImage(":/icons/main_power.png");
QStringList l2{QStringList{tr("Online"),tr("Input Voltage"),tr("Output Voltage"),tr("Output Current"),tr("Module Temp.")}};
QStringList l2{QStringList{tr("Online"),tr("Vin."),tr("Vout"),tr("Iout"),tr("T_mod")}};
m_pPowerPanel->setLableCount(l2.count());
m_pPowerPanel->setTableRowsCount(10);
m_pPowerPanel->setLables(l2);
@ -261,10 +348,12 @@ bool MainWindow::InitializeUI()
m_pPowerPanel->Build();
mainLayout->addWidget(m_pPowerPanel, 0, 1);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_POWER,m_pPowerPanel));
//电池
m_pBatteryPanel = new CustomDisplayPanel(this);
m_pBatteryPanel->setImage(":/icons/main_battery.png");
QStringList l3{QStringList{tr("Online"),tr("SOC"),tr("SOH"),tr("Group Voltage"),tr("Cell V.Avg"),tr("Cell V.Max"),tr("Cell V.Min")}};
QStringList l3{QStringList{tr("Online"),tr("SOC"),tr("SOH"),tr("Vpack")}};
m_pBatteryPanel->setLableCount(l3.count());
m_pBatteryPanel->setTableRowsCount(10);
m_pBatteryPanel->setLables(l3);
@ -273,6 +362,8 @@ bool MainWindow::InitializeUI()
m_pBatteryPanel->Build();
mainLayout->addWidget(m_pBatteryPanel, 0, 2);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_BATTERY,m_pBatteryPanel));
//空调
m_pACPanel = new CustomDisplayPanel(this);
m_pACPanel->setImage(":/icons/main_ac.png");
@ -285,10 +376,12 @@ bool MainWindow::InitializeUI()
m_pACPanel->Build();
mainLayout->addWidget(m_pACPanel, 0, 3);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_AC,m_pACPanel));
//交流配电
m_pInverterPanel = new CustomDisplayPanel(this);
m_pInverterPanel->setImage(":/icons/main_invertor.png");
QStringList l5{QStringList{tr("Online"),tr("Input Voltage"),tr("Input Current"),tr("Module Temp.")}};
QStringList l5{QStringList{tr("Online"),tr("Vin"),tr("Iin"),tr("T_mod")}};
m_pInverterPanel->setLableCount(l5.count());
m_pInverterPanel->setTableRowsCount(10);
m_pInverterPanel->setLables(l5);
@ -297,10 +390,12 @@ bool MainWindow::InitializeUI()
m_pInverterPanel->Build();
mainLayout->addWidget(m_pInverterPanel, 1, 0);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_INVERTER,m_pInverterPanel));
//PV太阳能
m_pPVPanel = new CustomDisplayPanel(this);
m_pPVPanel->setImage(":/icons/main_pv.png");
QStringList l6{QStringList{tr("Online"),tr("Output Voltage"),tr("Output Current"),tr("Module Temp.")}};
QStringList l6{QStringList{tr("Online"),tr("Vout"),tr("Iout"),tr("T_mod")}};
m_pPVPanel->setLableCount(l6.count());
m_pPVPanel->setTableRowsCount(10);
m_pPVPanel->setLables(l6);
@ -309,10 +404,12 @@ bool MainWindow::InitializeUI()
m_pPVPanel->Build();
mainLayout->addWidget(m_pPVPanel, 1, 1);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_PV,m_pPVPanel));
//门禁
m_pHomePanel = new CustomDisplayPanel(this);
m_pHomePanel->setImage(":/icons/main_cab.png");
QStringList l7{QStringList{tr("Online"),tr("Output Voltage"),tr("Output Current"),tr("Module Temp.")}};
QStringList l7{QStringList{tr("Online"),tr("Vout"),tr("Iout"),tr("T_mod")}};
m_pHomePanel->setLableCount(l7.count());
m_pHomePanel->setTableRowsCount(10);
m_pHomePanel->setLables(l7);
@ -321,6 +418,8 @@ bool MainWindow::InitializeUI()
m_pHomePanel->Build();
mainLayout->addWidget(m_pHomePanel, 1, 2);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_HOME,m_pHomePanel));
//告警
m_pAlarmPanel = new CustomWarningPanel(this);
m_pAlarmPanel->setImage(":/icons/main_alarm.png");
@ -334,6 +433,8 @@ bool MainWindow::InitializeUI()
m_pAlarmPanel->Build();
mainLayout->addWidget(m_pAlarmPanel, 1, 3);
m_Panels.insert(std::make_pair(CustomDisplayPanel::PANEL_ALARM,m_pAlarmPanel));
// 设置布局的间距和边距
mainLayout->setSpacing(5);
//mainLayout->setContentsMargins(10, 40, 10, 10); // 顶部留出工具栏空间
@ -364,11 +465,7 @@ bool MainWindow::InitializeUI()
QPixmap pixmap(":/icons/logo-en.png"); // 替换为实际图片路径
logoLabel->setPixmap(pixmap.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
toolBar->addWidget(logoLabel);
toolBar->addSeparator();
//添加按钮
toolBar->addAction(actionRead);
toolBar->addSeparator();
//toolBar->addSeparator();
// 添加间隔控件
QWidget *spacer = new QWidget();
@ -388,6 +485,7 @@ bool MainWindow::InitializeUI()
//customFont.setBold(true);
//label->setFont(customFont);
//label->setStyleSheet("color: #2E86C1;");
label->setStyleSheet(
"QLabel {"
//" font-family: 'Alimama DongFangDaKai';" // 需确保字体已加载
@ -404,6 +502,10 @@ bool MainWindow::InitializeUI()
spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolBar->addWidget(spacerWidget);
//添加按钮
toolBar->addAction(actionRead);
toolBar->addSeparator();
toolBar->addAction(actionSetting);
toolBar->addSeparator();
@ -429,6 +531,9 @@ bool MainWindow::InitializeModbus()
getConfiguration(iniFilePath);
QString jsonFilePath = appDir + QString::fromStdString("/emsshower.json");
ReadConfiguration(jsonFilePath);
m_bInitializeModbus = true;
switch (m_modbus_type)
{
@ -454,7 +559,7 @@ bool MainWindow::InitializeRtu()
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);
#if 1
int slave_id = m_modbus_slave_id;
//modbus_set_debug(m_pModbus, true);
modbus_set_slave(m_pModbus, slave_id); //设置modbus从机地址
@ -468,7 +573,7 @@ bool MainWindow::InitializeRtu()
t.tv_sec=0;
t.tv_usec=1000000; //设置modbus超时时间为1000毫秒
modbus_set_response_timeout(m_pModbus, t.tv_usec,t.tv_usec);
#endif
return true;
}
@ -559,6 +664,75 @@ bool MainWindow::readRegister(int addr,int nb,uint16_t* dest)
return true;
}
bool MainWindow::readRegister()
{
if(!InitializeModbus()) //这里有问题,如果是虚拟串口,连接的通常会返回成功
{
ui->statusbar->showMessage(tr("Failed to open Modbus device,Check modbus connection please!")); //打开MODBUS设备失败请检查设备连接情况!"));
return false;
}
//对每一个slave进行读取
//枚举每一个slave id这里因为实际上只有一个slave所以实际上只会执行一次循环
SlaveItems::iterator iter = m_total_slave_items.begin();
for(; iter!=m_total_slave_items.end(); iter++)
{
SlaveAddressItems::iterator iterAddress = iter->slave_address_items.begin();
for(; iterAddress!=iter->slave_address_items.end(); iterAddress++)
{
uint16_t* tab_reg = new uint16_t[iterAddress->quantity];
int regs = modbus_read_registers(m_pModbus, iterAddress->start_addr, iterAddress->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 = new GeneralDeviceData();
DecodeSync(registers, *iterAddress, pDevice);
OpenJson json;
CreateJson2(pDevice,json);
m_Panels[iterAddress->device_type]->UpdateData(json);
delete pDevice;
qDebug() << "decode an item";
}
}
return true;
}
void MainWindow::DecodeSync(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData)
{
GeneralDeviceData* pGeneralData = (GeneralDeviceData*)pData;
RegisterDataItems::const_iterator iter = sa.register_data_items.begin();
int idx = 0;
for(; iter!=sa.register_data_items.end(); iter++)
{
if (iter->second.skip ==0)
{
DisplayDataItem ddi;
ddi.device_type = sa.device_type;
ddi.display_location = iter->second.display;
ddi.order = iter->second.order;
ddi.precision = iter->second.precision;
ddi.title = iter->second.title_en;
ddi.unit = iter->second.unit;
ddi.value = array[idx];
pGeneralData->m_PanelDisplayDataItems.emplace_back(ddi);
}
idx++;
}
}
void MainWindow::startAsyncProcess(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity, DeviceData* pDevice)
{
QThread* thread = new QThread;
@ -595,6 +769,42 @@ void MainWindow::startAsyncProcess(const QVector<uint16_t>& array,int slave_id,i
qDebug() << "同步读取完成";
}
void MainWindow::startAsyncProcess2(const QVector<uint16_t> &array, const slaveAddress& sa,DeviceData *pData)
{
QThread* thread = new QThread;
DecodeWorker* worker = new DecodeWorker;
worker->moveToThread(thread);
worker->setSlaveAddress(sa);
// 连接线程启动信号和槽函数
connect(this, &MainWindow::startProcessing2, worker, &DecodeWorker::processRegisterData);
// 工作完成后退出线程
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 startProcessing2(array,sa, pData);
// 阻塞,等待线程结束
loop.exec();
qDebug() << "同步读取完成";
}
void MainWindow::ReadSerialPortData()
{
@ -608,9 +818,9 @@ void MainWindow::ReadSerialPortData()
}
else
{
m_pTimer->setInterval(10000); // 10秒
m_pTimer->setInterval(10 * 1000); // 10秒
connect(m_pTimer, &QTimer::timeout, this, &MainWindow::onTimeout);
ui->statusbar->showMessage(tr("Begin Readding"));
ui->statusbar->showMessage(tr("Begin Reading"));
m_pTimer->start();
onTimeout();
}
@ -618,7 +828,8 @@ void MainWindow::ReadSerialPortData()
void MainWindow::onTimeout()
{
readRegister(0,0,0);
//readRegister(0,0,0);
readRegister();
}
void MainWindow::SettingSerialPort()
@ -633,6 +844,7 @@ void MainWindow::SettingSerialPort()
// QMessageBox::information(this, "Cancel Clicked", "Cancel was clicked!");
}
bool MainWindow::CreateJson(DeviceData* pData,OpenJson& json)
{
int data_type = pData->m_device_type;
@ -648,10 +860,10 @@ bool MainWindow::CreateJson(DeviceData* pData,OpenJson& json)
nodeLabel[0]["title"] = "Online";
nodeLabel[1]["value"] = pTempData->TempValue;
nodeLabel[1]["title"] = "Temp(℃)";
nodeLabel[1]["title"] = "T (℃) ";
nodeLabel[2]["value"] = pTempData->HumidityValue;
nodeLabel[2]["title"] = "RH (%) ";
nodeLabel[2]["title"] = "RH (%)";
auto& nodeTable = json["table"];
int i = 0;
@ -720,3 +932,64 @@ bool MainWindow::CreateJson(DeviceData* pData,OpenJson& json)
return false;
}
bool MainWindow::CreateJson2(DeviceData* pData,OpenJson& json)
{
assert(pData);
GeneralDeviceData* pDevice = (GeneralDeviceData*)pData;
DisplayDataItems::const_iterator iter = pDevice->m_PanelDisplayDataItems.begin();
int idx0=0;
int idx1=0;
json["panel_type"] = iter->device_type;
if (iter->device_type == 6) //告警,需要特别处理
{
auto& nodeTable = json["alarm"];
for(; iter!=pDevice->m_PanelDisplayDataItems.end(); iter++)
{
if(iter->display_location == 0)
continue;
nodeTable[idx0]["time"] = QDateTime::currentDateTime().toString("MM-dd HH:mm:ss").toStdString();
nodeTable[idx0]["signal"] = iter->title;
nodeTable[idx0]["value"] = iter->value * 1.0f / iter->precision;
idx0++;
}
}
else
{
auto& nodeLabel = json["text_panel"];
auto& nodeTable = json["table"];
for(; iter!=pDevice->m_PanelDisplayDataItems.end(); iter++)
{
if(iter->display_location == 1) //显示在面板
{
nodeLabel[idx0]["value"] = iter->value * 1.0f / iter->precision;
nodeLabel[idx0]["title"] = iter->title;
idx0++;
}
if (iter->display_location == 2) // 显示在表格
{
if (idx1 == 0)
{
nodeTable[idx1]["value"] = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss").toStdString();
nodeTable[idx1]["signal"] = "Time";
}
else
{
nodeTable[idx1]["value"] = iter->value * 1.0f / iter->precision;
nodeTable[idx1]["signal"] = iter->title;
}
idx1++;
}
}
}
std::string a = json.encode();
qDebug() << QString::fromStdString(a);
return true;
}

View File

@ -42,12 +42,15 @@ public:
this->pDevice = pDevice;
}
void setSlaveAddress(const slaveAddress& sa);
private:
QVector<uint16_t> array;
int slave_id;
int start_addr;
int quantity;
DeviceData* pDevice;
slaveAddress m_slaveAddress;
signals:
// 处理进度信号
@ -59,6 +62,8 @@ public slots:
// 处理数组的槽函数
// 根据从机id、开始地址、寄存器数量三个变量进行辨别和解码处理
void processArray(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData);
void processRegisterData(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData);
};
//处理主界面
@ -72,12 +77,15 @@ public:
protected:
void getConfiguration(QString iniFilePath);
void ReadConfiguration(QString jsonFilePath);
bool InitializeUI();
bool InitializeModbus();
bool InitializeRtu();
bool InitializeTcp();
bool readRegister(int addr,int nb,uint16_t* dest);
bool readRegister();
private:
Ui::MainWindow *ui;
@ -99,9 +107,12 @@ protected:
QSettings* m_pSettings;
bool m_bInitializeModbus;
SlaveItems m_total_slave_items;
protected:
//异步处理数据
void startAsyncProcess(const QVector<uint16_t>& array,int slave_id,int start_addr,int quantity,DeviceData* pData);
void startAsyncProcess2(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData);
private slots:
void ReadSerialPortData();
@ -117,9 +128,12 @@ private:
CustomDisplayPanel* m_pAlarmPanel; //告警
CustomDisplayPanel* m_pInverterPanel; //逆变器
CustomDisplayPanel* m_pPVPanel; //太阳能
std::map<int,CustomDisplayPanel*> m_Panels;
private:
bool CreateJson(DeviceData* pData,OpenJson& json);
bool CreateJson2(DeviceData* pData,OpenJson& json);
void DecodeSync(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData); //同步解码
signals:
// 处理进度信号
@ -129,5 +143,6 @@ signals:
signals:
void startProcessing(const QVector<uint16_t>& array, int slave_id, int start_addr, int quantity, DeviceData* pData);
void startProcessing2(const QVector<uint16_t>& array,const slaveAddress& sa,DeviceData* pData);
};
#endif // MAINWINDOW_H

View File

@ -1,7 +1,9 @@
#ifndef SLAVE_DEFINE_H
#ifndef SLAVE_DEFINE_H
#define SLAVE_DEFINE_H
#include <vector>
#include <string>
#include <map>
typedef struct _tagSlave
{
@ -14,6 +16,20 @@ typedef struct _tagSlave
typedef std::vector<SlaveItem*> SlaveData;
//存储解码后的数据
typedef struct __DisplayDataItem
{
int device_type;
int order;
std::string title;
int precision;
int value;
std::string unit;
int display_location; //1:board 2:table
} DisplayDataItem;
typedef std::vector<DisplayDataItem> DisplayDataItems;
class DeviceData
{
public:
@ -29,6 +45,19 @@ public:
int m_device_online_state;
};
class GeneralDeviceData: public DeviceData
{
public:
GeneralDeviceData()
{
m_device_type = 8899;
m_device_online_state = 0;
}
virtual ~GeneralDeviceData() {}
public:
DisplayDataItems m_PanelDisplayDataItems;
};
class TemperatureData : public DeviceData
{
@ -43,8 +72,8 @@ public:
virtual ~TemperatureData() {}
public:
bool bDecodeAlarm;
bool bDecodeTemp;
bool bDecodeAlarm;
bool bDecodeTemp;
float TempValue;
float HumidityValue;
float DewPointValue;
@ -56,4 +85,79 @@ public:
int TempLowAlarm;
};
////////////////////////////////////////////////////////////////////
// //
// 以下数据结构是为了存取json配置文件设置 //
// 保存串口的从机号、寄存器开始地址、数量、寄存器数据描述等等信息 //
////////////////////////////////////////////////////////////////////
/****************************************************************
*
*
SlaveItems
slaveAddress
registryData
*
*
*****************************************************************/
//寄存器的数据,以及控制策略描述
typedef struct __registryData
{
__registryData():
comment(""), precision(1.0f), unit(""), title_chn("中文"), title_en("eng"), display(1), skip(0)
{}
std::string comment; // ":"在线状态", 注释字段,为了方便读,无实际意义
int order; // 定义解码的顺序从0开始数量 =slaveAddress.quantity
float precision; // " : 1, 精度,标注小数点用
std::string unit; // " : "", 单位
std::string title_chn; // " : 中文显示
std::string title_en; // " : 英文显示
int display; // " : 1, 是否显示0不显示1显示在board2显示在表格
int skip; //" : 0 //1跳过 0不跳过
} registryData;
//寄存器的数据数组
typedef std::map<int,registryData> RegisterDataItems;
typedef struct __slaveAddress
{
int start_addr; // ":40000, 寄存器地址
unsigned short quantity; // " : 9, 连续读取多少个寄存器
unsigned short bytes_per_register; // " : 2, 每个寄存器的字节数缺省是uint16,两个字节
std::string device_name_chn; // " : "温湿度", 该寄存器数组代表的设备名称
std::string device_name_eng; // " : "温湿度", 该寄存器数组代表的设备名称,英文
//标识本地址的数据是哪一个类型的设备
/*
PANEL_TEMPERATURE = 1,
PANEL_BATTERY = 2,
PANEL_POWER = 3,
PANEL_AC = 4,
PANEL_PV = 5,
PANEL_ALARM = 6,
PANEL_INVERTER = 7,
PANEL_OTHER = 88,
PANEL_HOME = 99,
* */
int device_type;
RegisterDataItems register_data_items; //寄存器数据,数组
} slaveAddress;
//需要读取的从机的地址信息
typedef std::vector<slaveAddress> SlaveAddressItems;
typedef struct __slaveItem
{
int slave_id; //从机ID
int function_code; //功能码缺省是3
SlaveAddressItems slave_address_items; //该从机ID需要读取的地址信息描述
} slaveItem;
//需要处理的从机列表
typedef std::vector<slaveItem> SlaveItems;
#endif // SLAVE_DEFINE_H