Добавлен модуль для работы с (0x2B / 0x0E) Read Device Identification

This commit is contained in:
Вячеслав Штейбезандт 2025-10-21 17:23:23 +03:00
parent e402334153
commit 3f1cd53e19
13 changed files with 831 additions and 79 deletions

View File

@ -32,6 +32,9 @@ SOURCES += \
main.cpp \
m3kte.cpp \
multiplesettings.cpp \
parameterbox.cpp \
parameterdevice.cpp \
parameterworkspace.cpp \
scanboard.cpp \
settingsdialog.cpp \
writeregistermodel.cpp
@ -43,6 +46,9 @@ HEADERS += \
lineringer.h \
m3kte.h \
multiplesettings.h \
parameterbox.h \
parameterdevice.h \
parameterworkspace.h \
scanboard.h \
settingsdialog.h \
writeregistermodel.h
@ -54,6 +60,9 @@ FORMS += \
lineringer.ui \
m3kte.ui \
multiplesettings.ui \
parameterbox.ui \
parameterdevice.ui \
parameterworkspace.ui \
scanboard.ui \
settingsdialog.ui

View File

@ -371,6 +371,8 @@ M3KTE::M3KTE(QWidget *parent)
m_debugTerminalDialog->setMainTerm(this);
m_regMultipleSettings = new MultipleSettings(this);
modbusDevice = new QModbusRtuSerialMaster(this);
m_parameterWorkspace = new ParameterWorkspace();
m_parameterWorkspace->setModbusClient(modbusDevice);
m_debugTerminalDialog->setModbusDevice(modbusDevice);
connect(this, &M3KTE::boardReading, m_debugTerminalDialog, &DebugTerminalDialog::boardDebugReading);
m_lineRinger = new LineRinger();
@ -382,18 +384,10 @@ M3KTE::M3KTE(QWidget *parent)
Boards[1].boardScanners->setSingleShot(true);
Boards[2].boardScanners->setSingleShot(true);
Boards[3].boardScanners->setSingleShot(true);
connect(Boards[0].boardScanners, &QTimer::timeout, this, [this]() {
boardScan(0);
});
connect(Boards[1].boardScanners, &QTimer::timeout, this, [this]() {
boardScan(1);
});
connect(Boards[2].boardScanners, &QTimer::timeout, this, [this]() {
boardScan(2);
});
connect(Boards[3].boardScanners, &QTimer::timeout, this, [this]() {
boardScan(3);
});
connect(Boards[0].boardScanners, &QTimer::timeout, this, [this]() {boardScan(0);});
connect(Boards[1].boardScanners, &QTimer::timeout, this, [this]() {boardScan(1);});
connect(Boards[2].boardScanners, &QTimer::timeout, this, [this]() {boardScan(2);});
connect(Boards[3].boardScanners, &QTimer::timeout, this, [this]() {boardScan(3);});
{
Boards[0].adr = 1;
Boards[1].adr = 2;
@ -459,13 +453,10 @@ M3KTE::M3KTE(QWidget *parent)
for(int i = 0; i < 4; i++)
{
connect(Boards[i].localState[LOCAL_STATE_POLL], &QCheckBox::clicked,
this, [i, this](bool checked) {
m_deviceSettingsDialog->sendPollCommand(i, checked);
});
this, [i, this](bool checked) {m_deviceSettingsDialog->sendPollCommand(i, checked);});
Boards[i].localState[LOCAL_STATE_WARN]->setAttribute(Qt::WA_TransparentForMouseEvents, true);
Boards[i].localState[LOCAL_STATE_ERR]->setAttribute(Qt::WA_TransparentForMouseEvents, true);
}
ui->BSM_Warning->setAttribute(Qt::WA_TransparentForMouseEvents, true);
ui->BSM_Accident->setAttribute(Qt::WA_TransparentForMouseEvents, true);
ui->BSM_WorkInProgress->setAttribute(Qt::WA_TransparentForMouseEvents, true);
@ -558,6 +549,7 @@ void M3KTE::initActions()
connect(m_regMultipleSettings, &MultipleSettings::writeAndSend, this, &M3KTE::slotmultipleRegWriteAndSend);
connect(ui->ConnectionMenuSettings, &QAction::triggered, m_settingsDialog, &QDialog::show);
connect(ui->M3kteMenuSettings, &QAction::triggered, m_deviceSettingsDialog, &QDialog::show);
connect(ui->ParameterScan, &QAction::triggered, m_parameterWorkspace, &QWidget::show);
}
void M3KTE::logError(const QString &errorPlace, const QString &errorString, unsigned errorCount, const QString &description)
@ -612,7 +604,9 @@ void M3KTE::onConnectClicked()
} else {
ui->ConnectionMenuConnect->setEnabled(false);
ui->ConnectionMenuDisconnect->setEnabled(true);
if(pingNetworkDevices()) { //Опрос устройств
if(pingNetworkDevices()) //Опрос устройст
{
//m_parameterWorkspace->setDeviceCount(1);
unsigned tmp_adr[4];
bool ActiveDevices[4];
for(int i = 0; i < 4; i++) {
@ -635,6 +629,7 @@ void M3KTE::onConnectClicked()
ui->BSM_Accident->setEnabled(true);
ui->BSM_WorkInProgress->setEnabled(true);
ui->BSM_WorkInProgress->setChecked(true);
ui->ParameterScan->setEnabled(true);
}
}
} else {
@ -677,6 +672,7 @@ void M3KTE::onConnectClicked()
ui->BSM_Accident->setEnabled(false);
ui->BSM_WorkInProgress->setEnabled(false);
ui->M3kteRegSettings->setEnabled(false);
ui->ParameterScan->setEnabled(false);
m_deviceSettingsDialog->onDisconnect();
m_debugTerminalDialog->offAllBoard();
}
@ -777,8 +773,7 @@ void M3KTE::onWriteButtonClicked()
connect(reply, &QModbusReply::finished, this, [this, reply, tmp_id]() {
if(reply->error() == QModbusDevice::ProtocolError) {
statusBar()->showMessage(tr("Write response error: %1 (Mobus exception: 0x%2)")
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16),
5000);
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16), 5000);
logError(tr("Плата %1 (ID %2)").arg(tmp_id+1).arg(Boards[tmp_id].adr),
reply->errorString(), ++Boards[tmp_id].error_TX,
QString::number(reply->rawResult().exceptionCode(), 16));
@ -1056,7 +1051,8 @@ void M3KTE::onSpeedUpdate()
QPointer<M3KTE> safeThis(this);
connect(this, &M3KTE::errorAtCheckBoards, this, [safeThis]() {
if (!safeThis) return;
if (!safeThis)
return;
safeThis->disconnect(safeThis, &M3KTE::errorAtCheckBoards, safeThis, nullptr);
safeThis->modbusDevice->setTimeout(safeThis->m_settingsDialog->settings().responseTime);
safeThis->revertToOldSpeedAndRestart();
@ -1064,7 +1060,8 @@ void M3KTE::onSpeedUpdate()
});
connect(this, &M3KTE::successAtCheckBoards, this, [safeThis]() {
if (!safeThis) return;
if (!safeThis)
return;
safeThis->disconnect(safeThis, &M3KTE::successAtCheckBoards, safeThis, nullptr);
safeThis->m_settingsDialog->UpdateBaud(safeThis->m_deviceSettingsDialog->currentSpeed());
safeThis->modbusDevice->setTimeout(safeThis->m_settingsDialog->settings().responseTime);
@ -1125,24 +1122,16 @@ void M3KTE::onParityUpdate()
modbusDevice->setTimeout(500);
QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 174, 1);
switch(m_deviceSettingsDialog->currentParity()) {
case 0: //Нет контроля
unit.setValue(0, 0x000);
break;
case 1: //Четный
unit.setValue(0, 0x0400);
break;
case 2: //Нечетный
unit.setValue(0, 0x0600);
break;
case 0: unit.setValue(0, 0x000); break; //Нет контроля
case 1: unit.setValue(0, 0x0400); break;//Четный
case 2: unit.setValue(0, 0x0600); break;//Нечетный
}
// Используем shared pointers вместо ссылок на стековые переменные
auto totalActiveBoards = QSharedPointer<int>::create(0);
auto confirmedBoards = QSharedPointer<int>::create(0);
auto pendingBoards = QSharedPointer<QSet<int>>::create();
auto oldParity = m_settingsDialog->curParity(); // сохраняем старую четность для отката
auto newParity = m_deviceSettingsDialog->currentParity();
// Лямбда для обработки результата
auto processResult = [this, totalActiveBoards, confirmedBoards, oldParity, newParity]() {
if(*confirmedBoards != *totalActiveBoards) {
@ -1152,7 +1141,6 @@ void M3KTE::onParityUpdate()
modbusDevice->disconnectDevice();
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, newParity);
modbusDevice->connectDevice();
auto errorHandler = [this, oldParity]() {
disconnect(this, &M3KTE::errorAtCheckBoards, this, nullptr);
modbusDevice->setTimeout(m_settingsDialog->settings().responseTime);
@ -1161,21 +1149,17 @@ void M3KTE::onParityUpdate()
modbusDevice->connectDevice();
beginScanBoards();
};
auto successHandler = [this, newParity]() {
disconnect(this, &M3KTE::successAtCheckBoards, this, nullptr);
m_settingsDialog->UpdateParity(newParity);
modbusDevice->setTimeout(m_settingsDialog->settings().responseTime);
beginScanBoards();
};
connect(this, &M3KTE::errorAtCheckBoards, this, errorHandler);
connect(this, &M3KTE::successAtCheckBoards, this, successHandler);
checkBoards();
}
};
for(int i = 0; i < 4; i++) {
if(!Boards[i].isActive)
continue;
@ -1184,7 +1168,6 @@ void M3KTE::onParityUpdate()
if(reply) {
(*totalActiveBoards)++;
pendingBoards->insert(slaveAdress);
connect(reply, &QModbusReply::finished, this,
[this, i, reply, slaveAdress, totalActiveBoards, confirmedBoards, pendingBoards, processResult]() {
if(reply->error() == QModbusDevice::TimeoutError) {
@ -1405,6 +1388,14 @@ bool M3KTE::pingNetworkDevices()
delete _unit_settings[2];
}
}
int totalBoardsActive = 0;
for(int i = 0; i < 4; i++)
{
if(Boards[i].isActive)
totalBoardsActive++;
}
m_parameterWorkspace->setDeviceCount(totalBoardsActive);
modbusDevice->setNumberOfRetries(m_settingsDialog->settings().numberOfRetries);
beginScanBoards();
bar->deleteLater();
@ -1413,11 +1404,13 @@ bool M3KTE::pingNetworkDevices()
void M3KTE::beginScanBoards()
{
int totalBoardsActive = 0;
for(int i = 0; i < 4; i++) {
if(Boards[i].isActive) {
m_debugTerminalDialog->setScanBoardActive(true, i);
m_deviceSettingsDialog->initPollForBoard(i, Boards[i].adr);
boardScan(i);
m_parameterWorkspace->updateDevice(totalBoardsActive++, Boards[i].isActive, Boards[i].adr);
}
}
return;
@ -1544,45 +1537,19 @@ void M3KTE::displayResultOfScan(QModbusReply *reply, int boardID, int status)
}
if (state) {
switch (numb_err) {
case 1:
statusText += QString(" (Err 5 VD)");
break;
case 2:
statusText += QString(" (Err 5 VA)");
break;
case 3:
statusText += QString(" (Err 5 Vsci)");
break;
case 4:
statusText += QString(" (Err 24 V)");
break;
case 5:
statusText += QString(" (Hardfault)");
break;
case 6:
statusText += QString(" (Empty Settings)");
break;
case 7:
statusText += QString(" (ADC Error)");
break;
case 8:
statusText += QString(" (Program Err 4)");
break;
case 9:
statusText += QString(" (Program Err 5)");
break;
case 10:
statusText += QString(" (EEPROM Error)");
break;
case 11:
statusText += QString(" (Unstable discharge)");
break;
case 12:
statusText += QString(" (RS/UART Errors)");
break;
default:
statusText += QString(" (Program Err %1)").arg(numb_err - 4);
break;
case 1: statusText += QString(" (Err 5 VD)"); break;
case 2: statusText += QString(" (Err 5 VA)"); break;
case 3: statusText += QString(" (Err 5 Vsci)"); break;
case 4: statusText += QString(" (Err 24 V)"); break;
case 5: statusText += QString(" (Hardfault)"); break;
case 6: statusText += QString(" (Empty Settings)"); break;
case 7: statusText += QString(" (ADC Error)"); break;
case 8: statusText += QString(" (Program Err 4)"); break;
case 9: statusText += QString(" (Program Err 5)"); break;
case 10: statusText += QString(" (EEPROM Error)"); break;
case 11: statusText += QString(" (Unstable discharge)"); break;
case 12: statusText += QString(" (RS/UART Errors)"); break;
default: statusText += QString(" (Program Err %1)").arg(numb_err - 4);
}
}
Boards[boardID].localError->setText(statusText);

View File

@ -12,6 +12,7 @@
#include "multiplesettings.h"
#include "scanboard.h"
#include "lineringer.h"
#include "parameterworkspace.h"
#include <QModbusTcpClient>
#include <QModbusRtuSerialMaster>
@ -65,8 +66,6 @@ private:
void applySettingsFromScan(QModbusReply *reply);
void multipleRegWrite();
void multipleRegSend();
void writeSingleCoil(int boardId, int coilAddress, bool value);
void writeSingleRegister(int boardId, int regAddress, quint16 value);
bool autoBaudRateScan();
void selectPositionOnTree(unsigned index);
signals:
@ -95,6 +94,8 @@ public:
~M3KTE();
QModbusClient* getModbusDevice() const { return modbusDevice; }
QModbusReply* readSingleCoil(int boardID, int coilAddress);
void writeSingleCoil(int boardId, int coilAddress, bool value);
void writeSingleRegister(int boardId, int regAddress, quint16 value);
private:
Ui::M3KTE *ui;
QTableWidget *loggerTable = nullptr;
@ -107,6 +108,7 @@ private:
DebugTerminalDialog *m_debugTerminalDialog = nullptr;
SettingsDialog *m_settingsDialog = nullptr;
MultipleSettings *m_regMultipleSettings = nullptr;
ParameterWorkspace *m_parameterWorkspace = nullptr;
ScanBoard *m_scanBoard = nullptr;
LineRinger *m_lineRinger = nullptr;
QGroupBox *Boards_Fields[4];

View File

@ -14643,6 +14643,7 @@
<string>Модули</string>
</property>
<addaction name="LineCall"/>
<addaction name="ParameterScan"/>
</widget>
<widget class="QMenu" name="DebugMenu">
<property name="title">
@ -14691,11 +14692,37 @@
<property name="text">
<string>Открыть</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
<property name="shortcutVisibleInContextMenu">
<bool>true</bool>
</property>
</action>
<action name="OpenADCBuff">
<property name="text">
<string>Буфер АЦП</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
<property name="shortcutVisibleInContextMenu">
<bool>true</bool>
</property>
</action>
<action name="ParameterScan">
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Сканировать параметры</string>
</property>
</action>
</widget>
<resources/>

View File

@ -0,0 +1,56 @@
#include "parameterbox.h"
#include "ui_parameterbox.h"
ParameterBox::ParameterBox(QWidget *parent, pboxMode Mode, quint16 objectID) :
QWidget(parent),
ui(new Ui::ParameterBox)
{
ui->setupUi(this);
boxMode = Mode;
ID = objectID;
switch (boxMode) {
case Info:
ui->adrLine->setHidden(true);
ui->valueBox->setHidden(true);
ui->sendButton->setHidden(true);
break;
case MTemplate:
break;
}
ui->objectIdLabel->setText("0x" + QString::number(ID, 16));
}
ParameterBox::~ParameterBox()
{
delete ui;
}
void ParameterBox::on_sendButton_clicked()
{
if(ui->valueBox->currentText().isEmpty())
{
return;
}
emit writeParameter(ui->adrLine->text().toInt(), ui->valueBox->currentText().toInt(nullptr, 16));
}
void ParameterBox::setData(QString data)
{
ui->nameLine->setText(data);
}
void ParameterBox::setData(QString name, QString adr, QStringList values)
{
switch (boxMode) {
case Info:
ui->nameLine->setText(name);
break;
case MTemplate:
ui->nameLine->setText(name);
ui->adrLine->setText(adr);
ui->valueBox->clear();
ui->valueBox->addItems(values);
break;
}
}

43
M3KTE_TERM/parameterbox.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef PARAMETERBOX_H
#define PARAMETERBOX_H
#include <QWidget>
namespace Ui {
class ParameterBox;
}
class ParameterBox : public QWidget
{
Q_OBJECT
public:
enum pboxMode{
Info = 0,
MTemplate = 1
};
enum objectType{
Coil = 0,
HR = 1
};
explicit ParameterBox(QWidget *parent = nullptr, pboxMode Mode = Info, quint16 objectID = 0x80);
~ParameterBox();
void setData(QString data);
void setData(QString name, QString adr, QStringList values);
quint16 getID(){return ID;}
objectType getType(){return type;}
signals:
void writeParameter(int adr, quint16 value);
private slots:
void on_sendButton_clicked();
private:
quint16 ID;
pboxMode boxMode;
objectType type = HR;
Ui::ParameterBox *ui;
};
#endif // PARAMETERBOX_H

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParameterBox</class>
<widget class="QWidget" name="ParameterBox">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>43</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLineEdit" name="adrLine">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="sendButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>SEND</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="nameLine">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="valueBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="objectIdLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,151 @@
#include "parameterdevice.h"
#include "ui_parameterdevice.h"
void sortParameterBoxesByID(QVector<ParameterBox*>& parameterBoxes) {
std::sort(parameterBoxes.begin(), parameterBoxes.end(),
[](ParameterBox* a, ParameterBox* b) {
return a->getID() < b->getID();
});
}
ParameterDevice::ParameterDevice(QWidget *parent) :
QWidget(parent),
ui(new Ui::ParameterDevice)
{
ui->setupUi(this);
updateTimer = new QTimer(this);
updateTimer->setSingleShot(true);
connect(updateTimer, &QTimer::timeout, this, &ParameterDevice::sortScrollArea);
}
ParameterDevice::~ParameterDevice()
{
delete ui;
}
void ParameterDevice::on_selectiveRadio_clicked()
{
ui->selectiveBox->setEnabled(true);
mode = selectiveRequest;
}
void ParameterDevice::on_fullRadio_clicked()
{
ui->selectiveBox->setEnabled(false);
mode = fullRequest;
}
void ParameterDevice::on_checkButton_clicked()
{
for (ParameterBox* box : parameterBoxes) {
if (box) {
box->deleteLater();
}
}
parameterBoxes.clear();
quint16 strAdr;
int cnt;
strAdr = ui->adrSpin->value();
switch (mode) {
case fullRequest:
strAdr = 0x80;
cnt = 128;
break;
case selectiveRequest:
cnt = ui->countSpin->value();
break;
}
QProgressDialog progressDialog("Обработка...", "Отмена", 0, cnt, this);
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setMinimumDuration(0); // показывать сразу
QEventLoop loop;
connect(this, &ParameterDevice::transmitEnd, &loop, &QEventLoop::quit);
for (int i = 0; i < cnt; i ++) {
// Обновляем прогресс
progressDialog.setValue(i);
if (progressDialog.wasCanceled()) {
break; // пользователь отменил
}
QByteArray data = QByteArray::fromHex("0E04");
data.append(strAdr+i);
QModbusRequest request(QModbusRequest::EncapsulatedInterfaceTransport, data);
emit read(request, strAdr+i);
loop.exec();
if(errorAtTransmit)
{
errorAtTransmit = false;
break;
}
}
progressDialog.setValue(cnt);
sortParameterBoxesByID(parameterBoxes);
sortScrollArea();
}
void ParameterDevice::setError(QString error)
{
QMessageBox::information(nullptr, "Получен ответ", error);
errorAtTransmit = true;
emit transmitEnd();
}
void ParameterDevice::on_adrSpin_valueChanged(int arg1)
{
ui->countSpin->setRange(1, 256-arg1);
}
void ParameterDevice::setAnswer(QString reply, quint16 objectID)
{
ParameterBox *newbox = new ParameterBox(nullptr, ParameterBox::Info, objectID);
newbox->setData(reply);
switch (newbox->getType()) {
case ParameterBox::Coil:
connect(newbox, &ParameterBox::writeParameter, this, [this](int adr, quint16 value){
emit writeSingleCoil(adr, (bool)value);
});
break;
case ParameterBox::HR:
connect(newbox, &ParameterBox::writeParameter, this, [this](int adr, quint16 value){
emit writeSingleRegister(adr, value);
});
break;
}
parameterBoxes.append(newbox);
emit transmitEnd();
// // Остановить, если уже запущен
// if (updateTimer->isActive()) {
// updateTimer->stop();
// }
// // Запустить с задержкой 6 секунд
// updateTimer->start(6000);
}
void ParameterDevice::sortScrollArea()
{
//sortParameterBoxesByID(parameterBoxes);
//ui->parameterBoxHubContents->layout()->deleteLater();
QLayout* pblayout = ui->parameterBoxHubContents->layout();
if (!pblayout) {
// Создайте новый лейаут, если его нет
pblayout = new QVBoxLayout(ui->parameterBoxHubContents);
ui->parameterBoxHubContents->setLayout(pblayout);
}
QLayoutItem *item;
while ((item = pblayout->takeAt(0)) != nullptr){
//delete item;
}
//ui->parameterBoxHubContents->setLayout(pblayout);
for (int i = 0; i < parameterBoxes.count(); i++) {
pblayout->addWidget(parameterBoxes.at(i));
}
ui->parameterBoxHubContents->update();
ui->parameterBoxHubContents->adjustSize();
ui->scrollArea->updateGeometry();
ui->scrollArea->viewport()->update();
}

View File

@ -0,0 +1,62 @@
#ifndef ParameterDevice_H
#define ParameterDevice_H
#include <QWidget>
#include <QModbusRequest>
#include "parameterbox.h"
#include <algorithm>
#include <QLayout>
#include <QTimer>
#include <QMessageBox>
#include <QProgressDialog>
void sortParameterBoxesByID(QVector<ParameterBox*>& parameterBoxes);
namespace Ui {
class ParameterDevice;
}
class ParameterDevice : public QWidget
{
Q_OBJECT
public:
enum requestMode{
fullRequest = 0,
selectiveRequest = 1
};
void setAnswer(QString reply, quint16 objectID);
void setError(QString error);
void setAdr(int _adr){adr = _adr;}
int getAdr(){return adr;}
bool errorAtTransmit = false;
explicit ParameterDevice(QWidget *parent = nullptr);
~ParameterDevice();
signals:
void read(QModbusRequest request, quint16 objectID);
void writeSingleCoil(int coilAddress, bool value);
void writeSingleRegister(int registerAddress, quint16 value);
void transmitEnd();
private slots:
void on_selectiveRadio_clicked();
void on_fullRadio_clicked();
void on_checkButton_clicked();
void on_adrSpin_valueChanged(int arg1);
private:
void sortScrollArea();
private:
int adr;
QTimer *updateTimer;
QVector<ParameterBox*>parameterBoxes;
requestMode mode = fullRequest;
Ui::ParameterDevice *ui;
};
#endif // ParameterDevice_H

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParameterDevice</class>
<widget class="QWidget" name="ParameterDevice">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>687</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Extended Objects</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="1">
<widget class="QGroupBox" name="selectiveBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QSpinBox" name="adrSpin">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="minimum">
<number>128</number>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Start Adr:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Count:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="countSpin">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QRadioButton" name="selectiveRadio">
<property name="text">
<string>Selective Request</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="checkButton">
<property name="text">
<string>Check</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="fullRadio">
<property name="text">
<string>Full Request</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="parameterBoxHubContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>380</width>
<height>450</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,124 @@
#include "parameterworkspace.h"
#include "ui_parameterworkspace.h"
ParameterWorkspace::ParameterWorkspace(QWidget *parent) :
QWidget(parent),
ui(new Ui::ParameterWorkspace)
{
ui->setupUi(this);
}
ParameterWorkspace::~ParameterWorkspace()
{
delete ui;
}
// QModbusRequest requestOfDeviceType(QModbusRequest::EncapsulatedInterfaceTransport, QByteArray::fromHex("0E0404"));
// auto *reply = modbusDevice->sendRawRequest(requestOfDeviceType, tmp_adr);
void ParameterWorkspace::setDeviceCount(int count)
{
for(const auto& device : deviceList)
{
device.tab->deleteLater();
device.device->deleteLater();
}
deviceList.clear();
for(int i = 0; i < ui->tabWidget->count(); i++)
ui->tabWidget->removeTab(i);
for(int i = 0; i < count; i++)
{
device* _device = new device();
deviceList.append(*_device);
deviceList[i].device = new ParameterDevice();
int newtab = ui->tabWidget->addTab(deviceList[i].device, tr("Device №%1").arg(i+1));
deviceList[i].tab = ui->tabWidget->widget(newtab);
connect(deviceList[i].device, &ParameterDevice::read, this, [this, i](QModbusRequest request, quint16 objectID){
readDeviceIdentification(deviceList[i].device, request, deviceList[i].adr, objectID);
});
connect(deviceList[i].device, &ParameterDevice::writeSingleCoil, this, [this, i](int coilAddress, bool value){
writeSingleCoil(deviceList[i].adr, coilAddress, value);
});
connect(deviceList[i].device, &ParameterDevice::writeSingleRegister, this, [this, i](int registerAddress, quint16 value){
writeSingleRegister(deviceList[i].adr, registerAddress, value);
});
}
}
void ParameterWorkspace::writeSingleCoil(int adr, int coilAddress, bool value)
{
if (!modbusDevice && modbusDevice->state() == QModbusDevice::ConnectedState)
return;
QModbusDataUnit unit(QModbusDataUnit::Coils, coilAddress, 1);
unit.setValue(0, value ? 1 : 0);
if (auto *reply = modbusDevice->sendWriteRequest(unit, adr)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() != QModbusDevice::NoError) {
//ERROR
}
reply->deleteLater();
});
} else {
reply->deleteLater();
}
}
}
void ParameterWorkspace::writeSingleRegister(int adr, int regAddress, quint16 value)
{
if (!modbusDevice && modbusDevice->state() == QModbusDevice::ConnectedState)
return;
QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, regAddress, 1);
unit.setValue(0, value);
if (auto *reply = modbusDevice->sendWriteRequest(unit, adr)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() != QModbusDevice::NoError) {
//ERROR
}
reply->deleteLater();
});
} else {
reply->deleteLater();
}
}
}
void ParameterWorkspace::readDeviceIdentification(ParameterDevice *device, QModbusRequest request, int adr, quint16 objectID)
{
if (!modbusDevice && modbusDevice->state() == QModbusDevice::ConnectedState)
return;
if(auto *reply = modbusDevice->sendRawRequest(request, adr))
{
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, device, reply, objectID](){
if(reply->error() == QModbusDevice::NoError)
{
QModbusResponse resp = reply->rawResult();
if(resp.data().size() >= MODBUS_REQUEST_PROTOCOL_INFO_LENGTH)
{
QString result = QString(resp.data().remove(0, MODBUS_REQUEST_PROTOCOL_INFO_LENGTH));
device->setAnswer(result, objectID);
}
}
else
{
device->setError(reply->errorString());
qDebug()<<"Получен ответ:" + reply->errorString();
}
reply->deleteLater();
});
}
}
else
{
device->setError("Unknow error");
}
}
void ParameterWorkspace::updateDevice(int ID, bool status, int adr)
{
deviceList[ID].isActive = status;
deviceList[ID].adr = adr;
deviceList[ID].device->setAdr(adr);
}

View File

@ -0,0 +1,53 @@
#ifndef PARAMETERWORKSPACE_H
#define PARAMETERWORKSPACE_H
#include <QWidget>
#include <QDebug>
#include <QModbusRequest>
#include <QModbusDataUnit>
#include <QModbusTcpClient>
#include <QModbusRtuSerialMaster>
#include <QtSerialBus/qtserialbusglobal.h>
#if QT_CONFIG(modbus_serialport)
#include <QSerialPort>
#endif
#include "parameterdevice.h"
#define MODBUS_REQUEST_PROTOCOL_INFO_LENGTH 8
namespace Ui {
class ParameterWorkspace;
}
class ParameterWorkspace : public QWidget
{
Q_OBJECT
public:
explicit ParameterWorkspace(QWidget *parent = nullptr);
~ParameterWorkspace();
public:
void setModbusClient(QModbusClient *device){modbusDevice = device;}
void setDeviceCount(int count);
void updateDevice(int deviceID, bool status, int adr);
private slots:
void readDeviceIdentification(ParameterDevice *board, QModbusRequest request, int adr, quint16 objectID);
void writeSingleCoil(int adr, int coilAddress, bool value);
void writeSingleRegister(int adr, int registerAddress, quint16 value);
private:
struct device{
bool isActive = false;
int adr = 1;
ParameterDevice *device = nullptr;
QWidget *tab = nullptr;
};
QVector<device> deviceList;
QModbusClient *modbusDevice = nullptr;
Ui::ParameterWorkspace *ui;
};
#endif // PARAMETERWORKSPACE_H

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParameterWorkspace</class>
<widget class="QWidget" name="ParameterWorkspace">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>610</width>
<height>646</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>