first commit, correct read, correct config ini

This commit is contained in:
2025-07-04 02:07:18 +07:00
commit d482560e7b
6 changed files with 473 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/cmake-build-release/
/cmake-build-debug/
/.idea/

89
CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View 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