|
|
|
@@ -1,3 +1,4 @@ |
|
|
|
#include "domain/active_register_repository.h" |
|
|
|
#include "domain/project_storage.h" |
|
|
|
#include "domain/register_repository.h" |
|
|
|
#include "services/hmi_editor_service.h" |
|
|
|
@@ -18,6 +19,7 @@ |
|
|
|
#include <QDockWidget> |
|
|
|
#include <QLabel> |
|
|
|
#include <QLineEdit> |
|
|
|
#include <QListWidget> |
|
|
|
#include <QSpinBox> |
|
|
|
#include <QTimer> |
|
|
|
|
|
|
|
@@ -42,6 +44,60 @@ public: |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
class RepeatedStatusGateway final : public PlcCommunicationGateway |
|
|
|
{ |
|
|
|
public: |
|
|
|
PlcCommunicationResult connectDevice( |
|
|
|
const PlcSerialConfiguration &) override |
|
|
|
{ |
|
|
|
connection_state = PlcConnectionState::Connecting; |
|
|
|
notifyStateChanged(); |
|
|
|
connection_state = PlcConnectionState::Connected; |
|
|
|
notifyStateChanged(); |
|
|
|
notifyStateChanged(); |
|
|
|
return {true, {}}; |
|
|
|
} |
|
|
|
|
|
|
|
void disconnectDevice() override |
|
|
|
{ |
|
|
|
connection_state = PlcConnectionState::Disconnected; |
|
|
|
notifyStateChanged(); |
|
|
|
} |
|
|
|
|
|
|
|
void setPollAddresses(const std::vector<RegisterAddress> &) override {} |
|
|
|
PlcConnectionState state() const override { return connection_state; } |
|
|
|
bool initialReadCompleted() const override { return false; } |
|
|
|
const std::string &lastError() const override { return last_error; } |
|
|
|
|
|
|
|
void setCallbacks( |
|
|
|
std::function<void()> state_callback, |
|
|
|
std::function<void(bool)> initial_callback, |
|
|
|
std::function<void()> cache_callback, |
|
|
|
std::function<void(const std::string &)> error_callback) override |
|
|
|
{ |
|
|
|
state_changed = std::move(state_callback); |
|
|
|
initial_read_changed = std::move(initial_callback); |
|
|
|
cache_updated = std::move(cache_callback); |
|
|
|
error_reported = std::move(error_callback); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
void notifyStateChanged() |
|
|
|
{ |
|
|
|
if (state_changed) |
|
|
|
{ |
|
|
|
state_changed(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
PlcConnectionState connection_state = PlcConnectionState::Disconnected; |
|
|
|
std::string last_error; |
|
|
|
std::function<void()> state_changed; |
|
|
|
std::function<void(bool)> initial_read_changed; |
|
|
|
std::function<void()> cache_updated; |
|
|
|
std::function<void(const std::string &)> error_reported; |
|
|
|
}; |
|
|
|
|
|
|
|
void require(bool condition, const std::string &message) |
|
|
|
{ |
|
|
|
if (!condition) |
|
|
|
@@ -273,6 +329,48 @@ void testPlcConfigurationUsesDialog() |
|
|
|
"PLC configuration action must open the dedicated configuration dialog"); |
|
|
|
} |
|
|
|
|
|
|
|
void testRepeatedPlcStatusNotificationsAreCoalesced() |
|
|
|
{ |
|
|
|
TestProjectStorage storage; |
|
|
|
ProjectService project_service(storage); |
|
|
|
HmiEditorService editor_service(project_service); |
|
|
|
LogicEditorService logic_editor_service(project_service); |
|
|
|
VirtualRegisterRepository virtual_repository; |
|
|
|
VirtualRegisterRepository plc_repository; |
|
|
|
ActiveRegisterRepository active_repository(virtual_repository); |
|
|
|
HmiRuntimeService runtime_service(active_repository); |
|
|
|
OfflineSimulationService simulation_service(virtual_repository); |
|
|
|
RuntimeModeService mode_service(project_service, simulation_service); |
|
|
|
RepeatedStatusGateway gateway; |
|
|
|
mode_service.configurePlc( |
|
|
|
gateway, active_repository, virtual_repository, plc_repository); |
|
|
|
MainWindow window( |
|
|
|
mode_service, |
|
|
|
project_service, |
|
|
|
editor_service, |
|
|
|
logic_editor_service, |
|
|
|
runtime_service); |
|
|
|
QListWidget *output = requiredChild<QListWidget>(window, "outputList"); |
|
|
|
const int initial_count = output->count(); |
|
|
|
|
|
|
|
const PlcCommunicationResult result = mode_service.connectPlc( |
|
|
|
{"COM3", 1, 9600, 8, 2, 1, 1000, 2, 200}); |
|
|
|
require(result.succeeded, "PLC connection setup must succeed"); |
|
|
|
QApplication::processEvents(); |
|
|
|
|
|
|
|
const QString expected = QStringLiteral("PLC 已连接,正在读取工程使用的 M/D 地址"); |
|
|
|
int matching_count = 0; |
|
|
|
for (int index = initial_count; index < output->count(); ++index) |
|
|
|
{ |
|
|
|
if (output->item(index)->text() == expected) |
|
|
|
{ |
|
|
|
++matching_count; |
|
|
|
} |
|
|
|
} |
|
|
|
require(matching_count == 1, |
|
|
|
"repeated PLC status callbacks must append one coalesced output message"); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace |
|
|
|
|
|
|
|
int main(int argc, char *argv[]) |
|
|
|
@@ -285,6 +383,7 @@ int main(int argc, char *argv[]) |
|
|
|
{ |
|
|
|
testModeActionsControlEditingAvailability(); |
|
|
|
testPlcConfigurationUsesDialog(); |
|
|
|
testRepeatedPlcStatusNotificationsAreCoalesced(); |
|
|
|
} |
|
|
|
catch (const std::exception &error) |
|
|
|
{ |
|
|
|
|