Procházet zdrojové kódy

feat: 支持PLC动态更新监控轮询地址

main
suyu před 1 měsícem
rodič
revize
d3843ef060
7 změnil soubory, kde provedl 89 přidání a 7 odebrání
  1. +34
    -4
      app/src/infrastructure/plc_communication_service.cpp
  2. +3
    -0
      app/src/infrastructure/plc_communication_service.h
  3. +35
    -3
      app/src/services/runtime_mode_service.cpp
  4. +4
    -0
      app/src/services/runtime_mode_service.h
  5. +9
    -0
      app/tests/plc_runtime_tests.cpp
  6. +2
    -0
      app/tests/plc_runtime_tests.pro
  7. +2
    -0
      app/tests/runtime_mode_service_tests.pro

+ 34
- 4
app/src/infrastructure/plc_communication_service.cpp Zobrazit soubor

@@ -170,8 +170,13 @@ void PlcCommunicationService::disconnectDevice()
void PlcCommunicationService::setPollAddresses(
const std::vector<RegisterAddress> &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<RegisterAddress> &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<RegisterAddress> addresses = pending_poll_addresses_;
applyPollAddresses(addresses);
}
});
}



+ 3
- 0
app/src/infrastructure/plc_communication_service.h Zobrazit soubor

@@ -54,6 +54,7 @@ private:
};

void rebuildPollBlocks();
void applyPollAddresses(const std::vector<RegisterAddress> &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<RegisterAddress> poll_addresses_;
std::vector<RegisterAddress> pending_poll_addresses_;
std::vector<PollBlock> 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<bool> initial_blocks_read_;


+ 35
- 3
app/src/services/runtime_mode_service.cpp Zobrazit soubor

@@ -178,7 +178,25 @@ PlcCommunicationResult RuntimeModeService::connectPlc(
{
return {false, "PLC 通信服务尚未配置"};
}
std::vector<RegisterAddress> addresses;
refreshPlcPollAddresses();
setInitialPlcReadCompleted(false);
return plc_gateway_->connectDevice(configuration);
}

void RuntimeModeService::setMonitorAddresses(
const std::vector<RegisterAddress> &addresses)
{
monitor_addresses_ = addresses;
refreshPlcPollAddresses();
}

void RuntimeModeService::refreshPlcPollAddresses()
{
if (plc_gateway_ == nullptr)
{
return;
}
std::vector<RegisterAddress> 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()


+ 4
- 0
app/src/services/runtime_mode_service.h Zobrazit soubor

@@ -14,6 +14,7 @@

#include <cstdint>
#include <functional>
#include <vector>

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<RegisterAddress> &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<void()> plc_status_changed_callback_;
std::vector<RegisterAddress> monitor_addresses_;
};

+ 9
- 0
app/tests/plc_runtime_tests.cpp Zobrazit soubor

@@ -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");


+ 2
- 0
app/tests/plc_runtime_tests.pro Zobrazit soubor

@@ -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 \


+ 2
- 0
app/tests/runtime_mode_service_tests.pro Zobrazit soubor

@@ -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 \


Načítá se…
Zrušit
Uložit