综合平台编程器项目的远程存储
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

188 satır
6.2 KiB

  1. #include "services/runtime_mode_service.h"
  2. #include "services/offline_simulation_service.h"
  3. #include "services/project_service.h"
  4. #include "domain/active_register_repository.h"
  5. #include "domain/project_storage.h"
  6. #include "domain/register_repository.h"
  7. #include <functional>
  8. #include <iostream>
  9. #include <stdexcept>
  10. #include <string>
  11. #include <utility>
  12. namespace {
  13. class TestProjectStorage final : public ProjectStorage
  14. {
  15. public:
  16. ProjectSaveResult save(const Project &, const std::string &) override
  17. {
  18. return {true, ProjectStorageError::None, {}};
  19. }
  20. ProjectLoadResult load(const std::string &) override
  21. {
  22. return {false, {}, ProjectStorageError::FileReadFailed, {}};
  23. }
  24. };
  25. class ReadyPlcGateway final : public PlcCommunicationGateway
  26. {
  27. public:
  28. PlcCommunicationResult connectDevice(const PlcSerialConfiguration &) override
  29. {
  30. connection_state = PlcConnectionState::Connected;
  31. if (state_changed)
  32. {
  33. state_changed();
  34. }
  35. return {true, {}};
  36. }
  37. void disconnectDevice() override
  38. {
  39. connection_state = PlcConnectionState::Disconnected;
  40. initial_read = false;
  41. }
  42. void setPollAddresses(
  43. const std::vector<RegisterAddress> &addresses) override
  44. {
  45. poll_addresses = addresses;
  46. }
  47. PlcConnectionState state() const override { return connection_state; }
  48. bool initialReadCompleted() const override { return initial_read; }
  49. PlcCommunicationError lastErrorType() const override
  50. {
  51. return PlcCommunicationError::None;
  52. }
  53. const std::string &lastError() const override { return last_error; }
  54. void setCallbacks(
  55. std::function<void()> state_callback,
  56. std::function<void(bool)> initial_callback,
  57. std::function<void()> cache_callback,
  58. std::function<void(const std::string &)> error_callback) override
  59. {
  60. state_changed = std::move(state_callback);
  61. initial_read_changed = std::move(initial_callback);
  62. cache_updated = std::move(cache_callback);
  63. error_reported = std::move(error_callback);
  64. }
  65. void completeInitialRead()
  66. {
  67. initial_read = true;
  68. if (initial_read_changed)
  69. {
  70. initial_read_changed(true);
  71. }
  72. }
  73. const std::vector<RegisterAddress> &pollAddresses() const
  74. {
  75. return poll_addresses;
  76. }
  77. private:
  78. PlcConnectionState connection_state = PlcConnectionState::Disconnected;
  79. bool initial_read = false;
  80. std::string last_error;
  81. std::function<void()> state_changed;
  82. std::function<void(bool)> initial_read_changed;
  83. std::function<void()> cache_updated;
  84. std::function<void(const std::string &)> error_reported;
  85. std::vector<RegisterAddress> poll_addresses;
  86. };
  87. void require(bool condition, const std::string &message)
  88. {
  89. if (!condition)
  90. {
  91. throw std::runtime_error(message);
  92. }
  93. }
  94. void testModeTransitions()
  95. {
  96. // 验证服务将 PLC 首读状态与领域模式切换规则正确组合
  97. TestProjectStorage storage;
  98. ProjectService project_service(storage);
  99. VirtualRegisterRepository virtual_repository;
  100. VirtualRegisterRepository plc_repository;
  101. ActiveRegisterRepository active_repository(virtual_repository);
  102. OfflineSimulationService simulation_service(virtual_repository);
  103. ReadyPlcGateway gateway;
  104. RuntimeModeService service(project_service, simulation_service);
  105. service.configurePlc(
  106. gateway, active_repository, virtual_repository, plc_repository);
  107. Project &project = project_service.editProject();
  108. project.alarmDefinitions.push_back(
  109. {"alarm-m", {RegisterArea::M, 12}, AlarmCondition::MOn, 0, "M alarm"});
  110. project.alarmDefinitions.push_back(
  111. {"alarm-d", {RegisterArea::D, 34}, AlarmCondition::DHigh, 100, "D alarm"});
  112. require(service.mode() == ApplicationMode::Editing,
  113. "service must start in editing mode");
  114. require(service.policy().allowsProjectEditing,
  115. "editing mode must allow project editing");
  116. require(service.enterOfflineRunning().succeeded,
  117. "editing mode must enter offline running");
  118. require(service.simulationState() == SimulationState::Running,
  119. "offline mode must start the software executor");
  120. require(service.policy().usesVirtualRegisters,
  121. "offline running must use virtual registers");
  122. require(service.enterOnlineRunning().error
  123. == ModeTransitionError::MustReturnToEditing,
  124. "running modes must not switch directly");
  125. require(service.enterEditing().succeeded,
  126. "offline running must return to editing");
  127. require(service.simulationState() == SimulationState::Stopped,
  128. "returning to editing must stop the software executor first");
  129. require(service.enterOnlineRunning().error
  130. == ModeTransitionError::InitialPlcReadRequired,
  131. "online running must require an initial PLC read");
  132. require(service.connectPlc(
  133. {"COM9", 1, 9600, 8, 2, 1, 1000, 2, 200}).succeeded,
  134. "PLC connection must be established before its initial read can complete");
  135. require(gateway.pollAddresses()
  136. == std::vector<RegisterAddress>({
  137. {RegisterArea::M, 12}, {RegisterArea::D, 34}}),
  138. "M and D alarm addresses must be included in PLC polling");
  139. gateway.completeInitialRead();
  140. require(service.initialPlcReadCompleted(),
  141. "service must retain the initial PLC read state");
  142. require(service.enterOnlineRunning().succeeded,
  143. "online running must start after an initial PLC read");
  144. require(service.simulationState() == SimulationState::Stopped,
  145. "online running must never start the software executor");
  146. require(service.policy().usesPlcRegisters,
  147. "online running must use PLC registers");
  148. require(!service.policy().runsLogicExecutor,
  149. "online running must keep the software executor stopped");
  150. }
  151. } // namespace
  152. int main()
  153. {
  154. try
  155. {
  156. // 运行模式只有这一组状态机边界测试
  157. testModeTransitions();
  158. }
  159. catch (const std::exception &error)
  160. {
  161. std::cerr << "runtime mode service tests failed: " << error.what() << '\n';
  162. return 1;
  163. }
  164. std::cout << "runtime mode service tests passed\n";
  165. return 0;
  166. }