first commit, correct read, correct config ini
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/cmake-build-release/
|
||||
/cmake-build-debug/
|
||||
/.idea/
|
||||
89
CMakeLists.txt
Normal file
89
CMakeLists.txt
Normal file
@@ -0,0 +1,89 @@
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
project(mbIoUniversal LANGUAGES CXX)
|
||||
|
||||
# Set the C++ standard to C++17
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOUIC ON) # Enable automatic processing of .ui files
|
||||
set(CMAKE_AUTORCC ON) # Enable automatic processing of .qrc files
|
||||
set(CMAKE_AUTOMOC ON) # Enable automatic processing of MOC files
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_PREFIX_PATH "C:/Qt/5.15.2/mingw81_64/lib/cmake")
|
||||
endif ()
|
||||
|
||||
set(QT_COMPONENTS Core Gui Widgets Network Svg OpenGL SerialBus SerialPort Charts)
|
||||
|
||||
find_package(Qt5 COMPONENTS
|
||||
${QT_COMPONENTS}
|
||||
REQUIRED)
|
||||
|
||||
add_definitions(-DQT_DEPRECATED_WARNINGS)
|
||||
|
||||
include_directories(Inc)
|
||||
file(GLOB_RECURSE PROJECT_SOURCES SOURCES "Src/*.*" "Inc/*.*")
|
||||
|
||||
# List your UI form files
|
||||
set(PROJECT_FORMS
|
||||
# windows.ui
|
||||
)
|
||||
|
||||
# List your resource files
|
||||
set(PROJECT_RESOURCES
|
||||
# resources.qrc
|
||||
)
|
||||
|
||||
# Add the executable target
|
||||
add_executable(${PROJECT_NAME}
|
||||
${PROJECT_SOURCES}
|
||||
${PROJECT_HEADERS}
|
||||
${PROJECT_FORMS}
|
||||
${PROJECT_RESOURCES}
|
||||
)
|
||||
|
||||
foreach(QT_LIB ${QT_COMPONENTS})
|
||||
target_link_libraries(${PROJECT_NAME} Qt5::${QT_LIB})
|
||||
endforeach(QT_LIB)
|
||||
|
||||
if (WIN32)
|
||||
set(DEBUG_SUFFIX)
|
||||
if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
set(DEBUG_SUFFIX "d")
|
||||
endif ()
|
||||
set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
|
||||
if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
|
||||
set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
|
||||
if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
|
||||
set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
|
||||
endif ()
|
||||
endif ()
|
||||
set(MINGW_BIN_DIR "C:/PROGRA~1/JETBRA~1/CLion/bin/mingw/bin") # <-- Укажите правильный путь
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${MINGW_BIN_DIR}/libstdc++-6.dll"
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>")
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${MINGW_BIN_DIR}/libgcc_s_seh-1.dll"
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>")
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${MINGW_BIN_DIR}/libwinpthread-1.dll"
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>")
|
||||
if (EXISTS "${QT_INSTALL_PATH}/plugins/")
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/")
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${QT_INSTALL_PATH}/plugins/"
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/")
|
||||
endif ()
|
||||
foreach (QT_LIB ${QT_COMPONENTS})
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll"
|
||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}>")
|
||||
endforeach (QT_LIB)
|
||||
endif ()
|
||||
68
Inc/mainwindow.h
Normal file
68
Inc/mainwindow.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QMutex>
|
||||
#include <QTableWidget>
|
||||
#include <QSettings>
|
||||
#include <QVector>
|
||||
#include <QModbusTcpClient>
|
||||
#include <QModbusDataUnit>
|
||||
#include <QTimer>
|
||||
|
||||
class ColoredSquare : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ColoredSquare(QWidget *parent = nullptr);
|
||||
void setColor(const QColor& color);
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
private:
|
||||
QColor m_color;
|
||||
};
|
||||
|
||||
class Mainwindows : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Mainwindows(QWidget *parent = nullptr);
|
||||
~Mainwindows() override;
|
||||
|
||||
private slots:
|
||||
void onStateChanged(QModbusDevice::State state);
|
||||
void onConnectButtonClicked();
|
||||
void onReadReady();
|
||||
void onPollTimer();
|
||||
|
||||
private:
|
||||
void createUIElements();
|
||||
void initModbusConnection();
|
||||
void writeRegister(int index);
|
||||
void readRegisters();
|
||||
void loadConfiguration();
|
||||
|
||||
QTableWidget* m_table;
|
||||
QString m_ipAddress;
|
||||
int m_port;
|
||||
QVector<int> m_buttonRegisters;
|
||||
QVector<int> m_indicatorRegisters;
|
||||
int m_buttonCount;
|
||||
int m_indicatorCount;
|
||||
QVector<QPushButton*> m_buttons;
|
||||
QVector<ColoredSquare*> m_squares;
|
||||
QVector<int> m_colorIndices;
|
||||
|
||||
QModbusTcpClient* m_modbusClient;
|
||||
QPushButton* m_connectButton;
|
||||
bool m_connected;
|
||||
int m_responseTimeout;
|
||||
int m_connectTimeout;
|
||||
int m_pollInterval;
|
||||
QTimer* m_pollTimer;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
20
Src/main.cpp
Normal file
20
Src/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
#include <QStyleFactory>
|
||||
#include <QDebug>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication give_me_a_name(argc, argv);
|
||||
//app->setStyle(QStyleFactory::create("Fusion"));
|
||||
//app->setStyle(QStyleFactory::create("windowsvista"));
|
||||
QApplication::setStyle("windowsvista");
|
||||
//app->setStyle(QStyleFactory::create("Windows"));
|
||||
//app->setStyle(QStyleFactory::create("Plastique"));
|
||||
|
||||
qDebug() << QApplication::style();
|
||||
|
||||
auto *window = new Mainwindows();
|
||||
window->show();
|
||||
//window->init();
|
||||
QApplication::exec();
|
||||
}
|
||||
276
Src/mainwindow.cpp
Normal file
276
Src/mainwindow.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
#include <QTableWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QTextCodec>
|
||||
#include <QVBoxLayout>
|
||||
#include <QThread>
|
||||
#include <QPainter>
|
||||
#include <QSettings>
|
||||
#include "mainwindow.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QModbusTcpClient>
|
||||
#include <QModbusDataUnit>
|
||||
#include <QUrl>
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
|
||||
ColoredSquare::ColoredSquare(QWidget *parent) : QWidget(parent), m_color(Qt::gray) {
|
||||
}
|
||||
|
||||
void ColoredSquare::setColor(const QColor& color) {
|
||||
m_color = color;
|
||||
update();
|
||||
}
|
||||
|
||||
void ColoredSquare::paintEvent(QPaintEvent *) {
|
||||
QPainter painter(this);
|
||||
painter.fillRect(rect(), m_color);
|
||||
}
|
||||
|
||||
Mainwindows::Mainwindows(QWidget *parent)
|
||||
: QWidget(parent), m_modbusClient(nullptr), m_connected(false) {
|
||||
|
||||
loadConfiguration();
|
||||
createUIElements();
|
||||
initModbusConnection();
|
||||
}
|
||||
|
||||
void Mainwindows::loadConfiguration() {
|
||||
const QString filePath = QCoreApplication::applicationDirPath() + "/config.ini";
|
||||
QSettings settings(filePath, QSettings::IniFormat);
|
||||
|
||||
settings.beginGroup("Connection");
|
||||
m_ipAddress = settings.value("ip", "127.0.0.1").toString();
|
||||
m_port = settings.value("port", 502).toInt();
|
||||
m_responseTimeout = settings.value("responseTimeout", 1000).toInt();
|
||||
m_connectTimeout = settings.value("connectTimeout", 3000).toInt();
|
||||
m_pollInterval = settings.value("timeBetweenPolls", 100).toInt();
|
||||
settings.endGroup();
|
||||
|
||||
qDebug() << "ip: " << m_ipAddress << "port: " << m_port;
|
||||
qDebug() << "responseTimeout: " << m_responseTimeout;
|
||||
qDebug() << "connectTimeout: " << m_connectTimeout;
|
||||
qDebug() << "poolInterval: " << m_pollInterval;
|
||||
|
||||
// Read registers configuration
|
||||
settings.beginGroup("Registers");
|
||||
m_buttonCount = settings.value("buttonCount", 0).toInt();
|
||||
m_indicatorCount = settings.value("indicatorCount", 0).toInt();
|
||||
|
||||
m_buttonRegisters.clear();
|
||||
m_indicatorRegisters.clear();
|
||||
|
||||
// Load button registers
|
||||
for(int i = 1; i <= m_buttonCount; ++i) {
|
||||
QString buttonKey = QString("button_reg%1").arg(i);
|
||||
int buttonReg = settings.value(buttonKey, 0).toInt();
|
||||
if(buttonReg > 0) {
|
||||
m_buttonRegisters.append(buttonReg);
|
||||
}
|
||||
}
|
||||
|
||||
// Load indicator registers
|
||||
for(int i = 1; i <= m_indicatorCount; ++i) {
|
||||
QString indicatorKey = QString("indicator_reg%1").arg(i);
|
||||
int indicatorReg = settings.value(indicatorKey, 0).toInt();
|
||||
if(indicatorReg > 0) {
|
||||
m_indicatorRegisters.append(indicatorReg);
|
||||
}
|
||||
}
|
||||
settings.endGroup();
|
||||
|
||||
qDebug() << "Loaded" << m_buttonCount << "buttons and" << m_indicatorCount << "indicators";
|
||||
qDebug() << "Button registers:" << m_buttonRegisters;
|
||||
qDebug() << "Indicator registers:" << m_indicatorRegisters;
|
||||
}
|
||||
|
||||
void Mainwindows::initModbusConnection() {
|
||||
m_modbusClient = new QModbusTcpClient(this);
|
||||
|
||||
// Set timeouts
|
||||
m_modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_ipAddress);
|
||||
m_modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port);
|
||||
m_modbusClient->setTimeout(m_responseTimeout);
|
||||
m_modbusClient->setNumberOfRetries(1);
|
||||
|
||||
connect(m_modbusClient, &QModbusClient::stateChanged,
|
||||
this, &Mainwindows::onStateChanged);
|
||||
|
||||
// Initialize poll timer
|
||||
m_pollTimer = new QTimer(this);
|
||||
m_pollTimer->setInterval(m_pollInterval);
|
||||
connect(m_pollTimer, &QTimer::timeout, this, &Mainwindows::onPollTimer);
|
||||
}
|
||||
|
||||
void Mainwindows::onStateChanged(QModbusDevice::State state) {
|
||||
if (state == QModbusDevice::ConnectedState) {
|
||||
m_connected = true;
|
||||
m_connectButton->setText("Disconnect");
|
||||
readRegisters();
|
||||
m_pollTimer->start(); // Start polling when connected
|
||||
} else if (state == QModbusDevice::UnconnectedState) {
|
||||
m_connected = false;
|
||||
m_connectButton->setText("Connect");
|
||||
m_pollTimer->stop(); // Stop polling when disconnected
|
||||
}
|
||||
}
|
||||
|
||||
void Mainwindows::onConnectButtonClicked() {
|
||||
if (!m_connected) {
|
||||
if (!m_modbusClient->connectDevice()) {
|
||||
QMessageBox::critical(this, tr("Connection Error"),
|
||||
tr("Could not connect to the Modbus device!"));
|
||||
}
|
||||
// Start connection timeout timer
|
||||
QTimer::singleShot(m_connectTimeout, this, [this]() {
|
||||
if (!m_connected) {
|
||||
m_modbusClient->disconnectDevice();
|
||||
QMessageBox::warning(this, tr("Connection Timeout"),
|
||||
tr("Connection attempt timed out!"));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
m_modbusClient->disconnectDevice();
|
||||
}
|
||||
}
|
||||
|
||||
void Mainwindows::onPollTimer() {
|
||||
if (m_connected) {
|
||||
readRegisters();
|
||||
}
|
||||
}
|
||||
|
||||
void Mainwindows::writeRegister(int index) {
|
||||
if (!m_connected) return;
|
||||
|
||||
QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, m_buttonRegisters[index], 1);
|
||||
|
||||
if (auto *reply = m_modbusClient->sendWriteRequest(writeUnit, 1)) {
|
||||
if (!reply->isFinished())
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
else
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
|
||||
void Mainwindows::readRegisters() {
|
||||
if (!m_connected) return;
|
||||
|
||||
// Read indicator registers
|
||||
for (int i = 0; i < m_indicatorCount; ++i) {
|
||||
if (i < m_indicatorRegisters.size()) {
|
||||
QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, m_indicatorRegisters[i], 1);
|
||||
if (auto *reply = m_modbusClient->sendReadRequest(readUnit, 1)) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, this, &Mainwindows::onReadReady);
|
||||
} else {
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read button registers
|
||||
for (int i = 0; i < m_buttonCount; ++i) {
|
||||
if (i < m_buttonRegisters.size()) {
|
||||
QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, m_buttonRegisters[i], 1);
|
||||
if (auto *reply = m_modbusClient->sendReadRequest(readUnit, 1)) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, this, &Mainwindows::onReadReady);
|
||||
} else {
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mainwindows::onReadReady() {
|
||||
auto reply = qobject_cast<QModbusReply *>(sender());
|
||||
if (!reply) return;
|
||||
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
int address = unit.startAddress();
|
||||
int value = unit.value(0);
|
||||
|
||||
// Handle indicators
|
||||
for (int i = 0; i < m_indicatorRegisters.size(); ++i) {
|
||||
if (address == m_indicatorRegisters[i]) {
|
||||
static const QColor colors[] = {Qt::gray, Qt::black, Qt::green};
|
||||
m_colorIndices[i] = value % 3;
|
||||
m_squares[i]->setColor(colors[m_colorIndices[i]]);
|
||||
qDebug() << "Indicator" << i << "address:" << address << "value:" << value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle buttons
|
||||
for (int i = 0; i < m_buttonRegisters.size(); ++i) {
|
||||
if (address == m_buttonRegisters[i]) {
|
||||
QStringList bName = {"Открыть", "Закрыть"};
|
||||
m_buttons[i]->setText(bName[value & 1]);
|
||||
qDebug() << "Button" << i << "address:" << address << "value:" << value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void Mainwindows::createUIElements() {
|
||||
auto* mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// Add connect button at the top
|
||||
m_connectButton = new QPushButton("Connect", this);
|
||||
connect(m_connectButton, &QPushButton::clicked, this, &Mainwindows::onConnectButtonClicked);
|
||||
mainLayout->addWidget(m_connectButton);
|
||||
|
||||
// Create table with maximum of buttons or indicators
|
||||
int rowCount = qMax(m_buttonCount, m_indicatorCount);
|
||||
m_table = new QTableWidget(rowCount, 2, this);
|
||||
|
||||
// Setup table properties
|
||||
m_table->verticalHeader()->setVisible(false);
|
||||
m_table->horizontalHeader()->setVisible(false);
|
||||
m_table->setShowGrid(false);
|
||||
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_table->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
|
||||
// Create UI elements
|
||||
for(int i = 0; i < rowCount; ++i) {
|
||||
if (i < m_buttonCount) {
|
||||
auto* button = new QPushButton(QString("Register %1").arg(m_buttonRegisters[i]), this);
|
||||
m_buttons.append(button);
|
||||
m_table->setCellWidget(i, 0, button);
|
||||
connect(button, &QPushButton::clicked, [this, i]() {
|
||||
writeRegister(i);
|
||||
});
|
||||
}
|
||||
|
||||
if (i < m_indicatorCount) {
|
||||
auto* square = new ColoredSquare(this);
|
||||
square->setFixedSize(m_table->rowHeight(i), m_table->rowHeight(i));
|
||||
m_squares.append(square);
|
||||
m_colorIndices.append(0);
|
||||
m_table->setCellWidget(i, 1, square);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust column sizes
|
||||
m_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||
m_table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
|
||||
m_table->setColumnWidth(0, 100);
|
||||
m_table->setColumnWidth(1, 100);
|
||||
|
||||
mainLayout->addWidget(m_table);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
Mainwindows::~Mainwindows() {
|
||||
if (m_pollTimer) {
|
||||
m_pollTimer->stop();
|
||||
}
|
||||
if (m_modbusClient && m_modbusClient->state() != QModbusDevice::UnconnectedState) {
|
||||
m_modbusClient->disconnectDevice();
|
||||
}
|
||||
}
|
||||
17
config.ini
Normal file
17
config.ini
Normal file
@@ -0,0 +1,17 @@
|
||||
[Connection]
|
||||
ip=192.168.8.222
|
||||
port=502
|
||||
responseTimeout=1000
|
||||
connectTimeout=2000
|
||||
timeBetweenPolls=100
|
||||
|
||||
[Registers]
|
||||
buttonCount=3
|
||||
indicatorCount=4
|
||||
button_reg1=3
|
||||
button_reg2=4
|
||||
button_reg3=5
|
||||
indicator_reg1=13
|
||||
indicator_reg2=14
|
||||
indicator_reg3=15
|
||||
indicator_reg4=16
|
||||
Reference in New Issue
Block a user