From d3843ef060d537f6322f714b801cb9634d9cd60d Mon Sep 17 00:00:00 2001 From: suyu <1643689728@qq.com> Date: Thu, 13 Aug 2026 15:40:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81PLC=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=9B=91=E6=8E=A7=E8=BD=AE=E8=AF=A2=E5=9C=B0?= =?UTF-8?q?=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plc_communication_service.cpp | 38 +++++++++++++++++-- .../plc_communication_service.h | 3 ++ app/src/services/runtime_mode_service.cpp | 38 +++++++++++++++++-- app/src/services/runtime_mode_service.h | 4 ++ app/tests/plc_runtime_tests.cpp | 9 +++++ app/tests/plc_runtime_tests.pro | 2 + app/tests/runtime_mode_service_tests.pro | 2 + 7 files changed, 89 insertions(+), 7 deletions(-) diff --git a/app/src/infrastructure/plc_communication_service.cpp b/app/src/infrastructure/plc_communication_service.cpp index 8009b99..30c68a3 100644 --- a/app/src/infrastructure/plc_communication_service.cpp +++ b/app/src/infrastructure/plc_communication_service.cpp @@ -170,8 +170,13 @@ void PlcCommunicationService::disconnectDevice() void PlcCommunicationService::setPollAddresses( const std::vector &addresses) { - poll_addresses_ = addresses; - rebuildPollBlocks(); + if (pending_reply_ != nullptr) + { + pending_poll_addresses_ = addresses; + poll_update_pending_ = true; + return; + } + applyPollAddresses(addresses); } PlcConnectionState PlcCommunicationService::state() const @@ -248,8 +253,27 @@ void PlcCommunicationService::rebuildPollBlocks() } } next_poll_block_ = 0; - initial_blocks_read_.assign(poll_blocks_.size(), false); - initial_read_completed_ = false; + if (!initial_read_completed_) + { + initial_blocks_read_.assign(poll_blocks_.size(), false); + } + else + { + initial_blocks_read_.clear(); + } +} + +void PlcCommunicationService::applyPollAddresses( + const std::vector &addresses) +{ + poll_addresses_ = addresses; + rebuildPollBlocks(); + poll_update_pending_ = false; + pending_poll_addresses_.clear(); + if (state_ == PlcConnectionState::Connected && pending_reply_ == nullptr) + { + pollNextBlock(); + } } void PlcCommunicationService::pollNextBlock() @@ -278,6 +302,7 @@ void PlcCommunicationService::pollNextBlock() handleReadFinished(reply, block); if (state_ == PlcConnectionState::Connected && reply->error() == QModbusDevice::NoError + && !poll_update_pending_ && block_index < initial_blocks_read_.size()) { initial_blocks_read_[block_index] = true; @@ -300,6 +325,11 @@ void PlcCommunicationService::pollNextBlock() pending_reply_ = nullptr; } reply->deleteLater(); + if (poll_update_pending_) + { + const std::vector addresses = pending_poll_addresses_; + applyPollAddresses(addresses); + } }); } diff --git a/app/src/infrastructure/plc_communication_service.h b/app/src/infrastructure/plc_communication_service.h index 4ccff23..0b85025 100644 --- a/app/src/infrastructure/plc_communication_service.h +++ b/app/src/infrastructure/plc_communication_service.h @@ -54,6 +54,7 @@ private: }; void rebuildPollBlocks(); + void applyPollAddresses(const std::vector &addresses); void pollNextBlock(); void handleReadFinished(QModbusReply *reply, PollBlock block); RegisterWriteResult sendBitWrite(const RegisterAddress &address, bool value); @@ -67,9 +68,11 @@ private: QTimer poll_timer_; PlcSerialConfiguration configuration_; std::vector poll_addresses_; + std::vector pending_poll_addresses_; std::vector poll_blocks_; std::size_t next_poll_block_ = 0; QModbusReply *pending_reply_ = nullptr; + bool poll_update_pending_ = false; PlcConnectionState state_ = PlcConnectionState::Disconnected; bool initial_read_completed_ = false; std::vector initial_blocks_read_; diff --git a/app/src/services/runtime_mode_service.cpp b/app/src/services/runtime_mode_service.cpp index bf263aa..82a0446 100644 --- a/app/src/services/runtime_mode_service.cpp +++ b/app/src/services/runtime_mode_service.cpp @@ -178,7 +178,25 @@ PlcCommunicationResult RuntimeModeService::connectPlc( { return {false, "PLC 通信服务尚未配置"}; } - std::vector addresses; + refreshPlcPollAddresses(); + setInitialPlcReadCompleted(false); + return plc_gateway_->connectDevice(configuration); +} + +void RuntimeModeService::setMonitorAddresses( + const std::vector &addresses) +{ + monitor_addresses_ = addresses; + refreshPlcPollAddresses(); +} + +void RuntimeModeService::refreshPlcPollAddresses() +{ + if (plc_gateway_ == nullptr) + { + return; + } + std::vector addresses = monitor_addresses_; const Project &project = project_service_.project(); for (const HmiPage &page : project.hmiPages) { @@ -211,9 +229,23 @@ PlcCommunicationResult RuntimeModeService::connectPlc( } } } + addresses.erase( + std::remove_if( + addresses.begin(), addresses.end(), + [](const RegisterAddress &address) { return !address.isValid(); }), + addresses.end()); + std::sort( + addresses.begin(), addresses.end(), + [](const RegisterAddress &left, const RegisterAddress &right) + { + if (left.area() != right.area()) + { + return left.area() == RegisterArea::M; + } + return left.index() < right.index(); + }); + addresses.erase(std::unique(addresses.begin(), addresses.end()), addresses.end()); plc_gateway_->setPollAddresses(addresses); - setInitialPlcReadCompleted(false); - return plc_gateway_->connectDevice(configuration); } void RuntimeModeService::disconnectPlc() diff --git a/app/src/services/runtime_mode_service.h b/app/src/services/runtime_mode_service.h index 392fbbf..eed98fc 100644 --- a/app/src/services/runtime_mode_service.h +++ b/app/src/services/runtime_mode_service.h @@ -14,6 +14,7 @@ #include #include +#include class ProjectService; class ActiveRegisterRepository; @@ -74,6 +75,8 @@ public: RegisterRepository &virtual_repository, RegisterRepository &plc_repository); PlcCommunicationResult connectPlc(const PlcSerialConfiguration &configuration); + void setMonitorAddresses(const std::vector &addresses); + void refreshPlcPollAddresses(); void disconnectPlc(); PlcConnectionState plcConnectionState() const; const std::string &plcError() const; @@ -90,4 +93,5 @@ private: RegisterRepository *virtual_repository_ = nullptr; RegisterRepository *plc_repository_ = nullptr; std::function plc_status_changed_callback_; + std::vector monitor_addresses_; }; diff --git a/app/tests/plc_runtime_tests.cpp b/app/tests/plc_runtime_tests.cpp index 40496a5..e21d67e 100644 --- a/app/tests/plc_runtime_tests.cpp +++ b/app/tests/plc_runtime_tests.cpp @@ -178,6 +178,15 @@ void testRuntimeRepositorySwitchingAndDisconnect() {"COM9", 2, 19200, 8, 2, 1, 1000, 2, 200}); require(connected.succeeded && gateway.poll_addresses.size() == 1U, "PLC connection must receive the project address poll set"); + service.setMonitorAddresses({ + RegisterAddress{RegisterArea::M, 5}, + RegisterAddress{RegisterArea::D, 8}}); + require(gateway.poll_addresses.size() == 2U + && gateway.poll_addresses.front() + == RegisterAddress{RegisterArea::M, 5} + && gateway.poll_addresses.back() + == RegisterAddress{RegisterArea::D, 8}, + "monitor addresses must merge with and deduplicate project poll addresses"); require(service.enterOnlineRunning().error == ModeTransitionError::InitialPlcReadRequired, "online mode must wait for the first valid PLC read"); diff --git a/app/tests/plc_runtime_tests.pro b/app/tests/plc_runtime_tests.pro index 762aa23..111da01 100644 --- a/app/tests/plc_runtime_tests.pro +++ b/app/tests/plc_runtime_tests.pro @@ -13,6 +13,7 @@ SOURCES += \ ../src/domain/register_address.cpp \ ../src/domain/register_repository.cpp \ ../src/domain/active_register_repository.cpp \ + ../src/domain/register_monitor_model.cpp \ ../src/domain/hmi_model.cpp \ ../src/domain/control_logic_model.cpp \ ../src/domain/project_model.cpp \ @@ -27,6 +28,7 @@ HEADERS += \ ../src/domain/register_address.h \ ../src/domain/register_repository.h \ ../src/domain/active_register_repository.h \ + ../src/domain/register_monitor_model.h \ ../src/domain/hmi_model.h \ ../src/domain/control_logic_model.h \ ../src/domain/project_model.h \ diff --git a/app/tests/runtime_mode_service_tests.pro b/app/tests/runtime_mode_service_tests.pro index 1278410..2bb8996 100644 --- a/app/tests/runtime_mode_service_tests.pro +++ b/app/tests/runtime_mode_service_tests.pro @@ -13,6 +13,7 @@ SOURCES += \ ../src/domain/register_address.cpp \ ../src/domain/register_repository.cpp \ ../src/domain/active_register_repository.cpp \ + ../src/domain/register_monitor_model.cpp \ ../src/domain/hmi_model.cpp \ ../src/domain/control_logic_model.cpp \ ../src/domain/project_model.cpp \ @@ -26,6 +27,7 @@ HEADERS += \ ../src/domain/register_address.h \ ../src/domain/register_repository.h \ ../src/domain/active_register_repository.h \ + ../src/domain/register_monitor_model.h \ ../src/domain/hmi_model.h \ ../src/domain/control_logic_model.h \ ../src/domain/project_model.h \