综合平台编程器项目的远程存储
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

353 строки
13 KiB

  1. #include "runtime_panel_controller.h"
  2. #include "free_monitor_widget.h"
  3. #include "hmi_editor_widget.h"
  4. #include "logic_editor_widget.h"
  5. #include "runtime_monitor_widget.h"
  6. #include "runtime_monitor_window.h"
  7. #include "services/alarm_service.h"
  8. #include "services/hmi_editor_service.h"
  9. #include "services/hmi_navigation_service.h"
  10. #include "services/hmi_runtime_service.h"
  11. #include "services/logic_editor_service.h"
  12. #include "services/offline_simulation_service.h"
  13. #include "services/project_service.h"
  14. #include "services/register_monitor_service.h"
  15. #include "services/runtime_mode_service.h"
  16. #include <QListWidget>
  17. #include <QLabel>
  18. #include <QObject>
  19. #include <QTimer>
  20. #include <QWidget>
  21. #include <utility>
  22. namespace {
  23. QString fromUtf8(const std::string &value)
  24. {
  25. return QString::fromUtf8(value.data(), static_cast<int>(value.size()));
  26. }
  27. } // namespace
  28. RuntimePanelController::RuntimePanelController(
  29. QWidget &parent,
  30. RuntimeModeService &runtime_mode_service,
  31. ProjectService &project_service,
  32. HmiEditorService &hmi_editor_service,
  33. HmiRuntimeService &hmi_runtime_service,
  34. LogicEditorService &logic_editor_service,
  35. HmiNavigationService &hmi_navigation_service,
  36. AlarmService &alarm_service,
  37. RegisterMonitorService &register_monitor_service,
  38. HmiEditorWidget &hmi_editor_widget,
  39. LogicEditorWidget &logic_editor_widget,
  40. QLabel &executor_status_label,
  41. std::function<std::string()> current_logic_id,
  42. std::function<void(const std::string &)> select_logic,
  43. std::function<void(const std::string &)> show_logic_properties,
  44. StatusReporter status_reporter,
  45. OutputReporter output_reporter,
  46. RuntimeExitRequester runtime_exit_requester)
  47. : parent_(parent),
  48. runtime_mode_service_(runtime_mode_service),
  49. project_service_(project_service),
  50. hmi_editor_service_(hmi_editor_service),
  51. hmi_runtime_service_(hmi_runtime_service),
  52. logic_editor_service_(logic_editor_service),
  53. hmi_navigation_service_(hmi_navigation_service),
  54. alarm_service_(alarm_service),
  55. register_monitor_service_(register_monitor_service),
  56. hmi_editor_widget_(hmi_editor_widget),
  57. logic_editor_widget_(logic_editor_widget),
  58. executor_status_label_(executor_status_label),
  59. current_logic_id_(std::move(current_logic_id)),
  60. select_logic_(std::move(select_logic)),
  61. show_logic_properties_(std::move(show_logic_properties)),
  62. status_reporter_(std::move(status_reporter)),
  63. output_reporter_(std::move(output_reporter)),
  64. runtime_exit_requester_(std::move(runtime_exit_requester))
  65. {
  66. }
  67. RuntimePanelController::~RuntimePanelController() = default;
  68. void RuntimePanelController::configure()
  69. {
  70. runtime_monitor_window_ = std::make_unique<RuntimeMonitorWindow>(&parent_);
  71. runtime_monitor_window_->setObjectName(
  72. QStringLiteral("runtimeMonitorWindow"));
  73. runtime_monitor_widget_ = new RuntimeMonitorWidget(
  74. hmi_editor_service_,
  75. hmi_runtime_service_,
  76. logic_editor_service_,
  77. project_service_,
  78. hmi_navigation_service_,
  79. alarm_service_,
  80. register_monitor_service_,
  81. runtime_monitor_window_.get());
  82. runtime_monitor_widget_->setObjectName(QStringLiteral("runtimeMonitorWidget"));
  83. runtime_monitor_window_->setMonitorWidget(*runtime_monitor_widget_);
  84. QObject::connect(runtime_monitor_widget_, &RuntimeMonitorWidget::exitRequested,
  85. &parent_, [this]
  86. {
  87. if (runtime_exit_requester_)
  88. {
  89. runtime_exit_requester_();
  90. }
  91. });
  92. QObject::connect(runtime_monitor_widget_->freeMonitorWidget(),
  93. &FreeMonitorWidget::monitorAddressesChanged,
  94. &parent_, [this]
  95. {
  96. runtime_mode_service_.setMonitorAddresses(
  97. register_monitor_service_.addresses());
  98. runtime_monitor_widget_->refreshValues(
  99. runtime_mode_service_.mode(),
  100. runtime_mode_service_.plcConnectionState());
  101. });
  102. QObject::connect(runtime_monitor_widget_->freeMonitorWidget(),
  103. &FreeMonitorWidget::operationMessage,
  104. &parent_, [this](const QString &message)
  105. {
  106. status_reporter_(message, 4000);
  107. });
  108. QObject::connect(runtime_monitor_widget_, &RuntimeMonitorWidget::navigationFailed,
  109. &parent_, [this](const QString &message)
  110. {
  111. status_reporter_(message, 5000);
  112. output_reporter_(QObject::tr("页面导航失败:%1").arg(message));
  113. });
  114. runtime_refresh_timer_ = new QTimer(&parent_);
  115. runtime_refresh_timer_->setInterval(150);
  116. QObject::connect(runtime_refresh_timer_, &QTimer::timeout,
  117. &parent_, [this] { handleRuntimeTimer(); });
  118. runtime_refresh_timer_->start();
  119. QObject::connect(&runtime_mode_service_.offlineSimulationService(),
  120. &OfflineSimulationService::stateChanged,
  121. &parent_, [this] { handleSimulationStateChanged(); },
  122. Qt::QueuedConnection);
  123. QObject::connect(&runtime_mode_service_.offlineSimulationService(),
  124. &OfflineSimulationService::scanCompleted,
  125. &parent_, [this] { handleScanCompleted(); },
  126. Qt::QueuedConnection);
  127. QObject::connect(&runtime_mode_service_.onlineLogicMonitorService(),
  128. &OnlineLogicMonitorService::stateChanged,
  129. &parent_, [this] { handleSimulationStateChanged(); });
  130. QObject::connect(&runtime_mode_service_.onlineLogicMonitorService(),
  131. &OnlineLogicMonitorService::scanCompleted,
  132. &parent_, [this] { handleScanCompleted(); },
  133. Qt::QueuedConnection);
  134. }
  135. RuntimeMonitorWidget *RuntimePanelController::runtimeMonitorWidget() const
  136. {
  137. return runtime_monitor_widget_;
  138. }
  139. void RuntimePanelController::enterRuntime(
  140. const std::string &page_id,
  141. const std::string &logic_id,
  142. ApplicationMode mode,
  143. PlcConnectionState plc_state)
  144. {
  145. if (!runtime_session_active_)
  146. {
  147. runtime_monitor_widget_->setProjectObjects(page_id, logic_id);
  148. // 运行窗口只创建一次,后续进入运行态复用同一个监控投影
  149. runtime_session_active_ = true;
  150. }
  151. runtime_monitor_widget_->setMode(mode, plc_state);
  152. runtime_monitor_window_->showForRuntime();
  153. }
  154. void RuntimePanelController::leaveRuntime(
  155. ApplicationMode mode, PlcConnectionState plc_state)
  156. {
  157. runtime_session_active_ = false;
  158. runtime_monitor_widget_->setMode(mode, plc_state);
  159. runtime_monitor_window_->hideForEditing();
  160. }
  161. void RuntimePanelController::closeForApplicationExit()
  162. {
  163. if (runtime_monitor_window_ != nullptr)
  164. {
  165. runtime_monitor_window_->closeForApplicationExit();
  166. }
  167. }
  168. void RuntimePanelController::updateSimulationUi(bool report_fault)
  169. {
  170. const bool offline = runtime_mode_service_.mode()
  171. == ApplicationMode::OfflineRunning;
  172. const bool online = runtime_mode_service_.mode()
  173. == ApplicationMode::OnlineRunning;
  174. const bool plc_connected = runtime_mode_service_.plcConnectionState()
  175. == PlcConnectionState::Connected;
  176. const SimulationState state = runtime_mode_service_.simulationState();
  177. const bool write_enabled = (online && plc_connected)
  178. || (offline && state == SimulationState::Running);
  179. // 编辑画布始终只读,运行操作统一由运行监控中的 HMI 发出
  180. hmi_editor_widget_.setRuntimeWriteEnabled(false);
  181. if (runtime_monitor_widget_ != nullptr)
  182. {
  183. runtime_monitor_widget_->setHmiWriteEnabled(write_enabled);
  184. runtime_monitor_widget_->setFreeMonitorWriteEnabled(write_enabled);
  185. runtime_monitor_widget_->refreshValues(
  186. runtime_mode_service_.mode(),
  187. runtime_mode_service_.plcConnectionState());
  188. }
  189. if (online)
  190. {
  191. switch (runtime_mode_service_.onlineLogicMonitorService().state())
  192. {
  193. case OnlineLogicMonitorState::Running:
  194. {
  195. executor_status_label_.setText(
  196. QObject::tr("本地推算轨迹:运行(%1 次)")
  197. .arg(runtime_mode_service_.onlineLogicMonitorService()
  198. .successfulScanCount()));
  199. return;
  200. }
  201. case OnlineLogicMonitorState::Faulted:
  202. {
  203. executor_status_label_.setText(QObject::tr("本地推算轨迹:故障"));
  204. if (report_fault)
  205. {
  206. const LogicScanResult &error = runtime_mode_service_
  207. .onlineLogicMonitorService().lastError();
  208. const QString message = QObject::tr("真机本地轨迹异常:%1")
  209. .arg(fromUtf8(error.message));
  210. status_reporter_(message, 0);
  211. output_reporter_(message);
  212. }
  213. return;
  214. }
  215. case OnlineLogicMonitorState::Stopped:
  216. default:
  217. {
  218. executor_status_label_.setText(QObject::tr("本地推算轨迹:停止"));
  219. return;
  220. }
  221. }
  222. }
  223. switch (state)
  224. {
  225. case SimulationState::Running:
  226. {
  227. executor_status_label_.setText(
  228. QObject::tr("逻辑执行器:运行(%1 次)")
  229. .arg(runtime_mode_service_.successfulScanCount()));
  230. break;
  231. }
  232. case SimulationState::Faulted:
  233. {
  234. executor_status_label_.setText(QObject::tr("逻辑执行器:故障"));
  235. if (!report_fault)
  236. {
  237. break;
  238. }
  239. const LogicScanResult &error = runtime_mode_service_.simulationError();
  240. if (!error.logicId.empty()
  241. && logic_editor_service_.findLogic(error.logicId) != nullptr)
  242. {
  243. select_logic_(error.logicId);
  244. }
  245. const std::string logic_id = current_logic_id_();
  246. logic_editor_widget_.setLogicId(logic_id);
  247. if (runtime_monitor_widget_ != nullptr)
  248. {
  249. runtime_monitor_widget_->setProjectObjects(
  250. hmi_navigation_service_.currentPageId(), logic_id);
  251. }
  252. logic_editor_widget_.setRuntimeTrace(
  253. runtime_mode_service_.offlineSimulationService()
  254. .traceSnapshot().forLogic(logic_id),
  255. error.nodeId);
  256. if (runtime_monitor_widget_ != nullptr)
  257. {
  258. runtime_monitor_widget_->setLogicTrace(
  259. runtime_mode_service_.offlineSimulationService().traceSnapshot(),
  260. error.nodeId);
  261. }
  262. if (!error.nodeId.empty())
  263. {
  264. logic_editor_widget_.selectNode(error.nodeId);
  265. show_logic_properties_(error.nodeId);
  266. }
  267. QString message = QObject::tr("离线仿真异常:%1").arg(fromUtf8(error.message));
  268. if (!error.logicId.empty())
  269. {
  270. message += QObject::tr(",逻辑 %1").arg(fromUtf8(error.logicId));
  271. }
  272. if (!error.rungId.empty())
  273. {
  274. message += QObject::tr(",网络 %1").arg(fromUtf8(error.rungId));
  275. }
  276. if (!error.nodeId.empty())
  277. {
  278. message += QObject::tr(",节点 %1").arg(fromUtf8(error.nodeId));
  279. }
  280. status_reporter_(message, 0);
  281. output_reporter_(message);
  282. break;
  283. }
  284. case SimulationState::Stopped:
  285. default:
  286. {
  287. executor_status_label_.setText(QObject::tr("逻辑执行器:停止"));
  288. break;
  289. }
  290. }
  291. }
  292. void RuntimePanelController::handleRuntimeTimer()
  293. {
  294. // 定时器只刷新投影;离线按定时器扫描,真机在完整 PLC 轮询后推算
  295. if (runtime_mode_service_.mode() == ApplicationMode::Editing)
  296. {
  297. return;
  298. }
  299. alarm_service_.refresh();
  300. hmi_editor_widget_.refreshRuntimeValues();
  301. if (runtime_monitor_widget_ != nullptr)
  302. {
  303. runtime_monitor_widget_->refreshValues(
  304. runtime_mode_service_.mode(),
  305. runtime_mode_service_.plcConnectionState());
  306. }
  307. updateSimulationUi(false);
  308. }
  309. void RuntimePanelController::handleSimulationStateChanged()
  310. {
  311. updateSimulationUi(true);
  312. }
  313. void RuntimePanelController::handleScanCompleted()
  314. {
  315. const ApplicationMode mode = runtime_mode_service_.mode();
  316. const bool offline_running = mode == ApplicationMode::OfflineRunning
  317. && runtime_mode_service_.simulationState() == SimulationState::Running;
  318. const bool online_running = mode == ApplicationMode::OnlineRunning
  319. && runtime_mode_service_.onlineLogicMonitorService().state()
  320. == OnlineLogicMonitorState::Running;
  321. // 排队信号可能晚于退出操作到达,编辑态不得恢复旧运行轨迹
  322. if (!offline_running && !online_running)
  323. {
  324. return;
  325. }
  326. const std::string logic_id = current_logic_id_();
  327. const LogicTraceSnapshot &trace = offline_running
  328. ? runtime_mode_service_.offlineSimulationService().traceSnapshot()
  329. : runtime_mode_service_.onlineLogicMonitorService().traceSnapshot();
  330. logic_editor_widget_.setRuntimeTrace(trace.forLogic(logic_id));
  331. if (runtime_monitor_widget_ != nullptr)
  332. {
  333. runtime_monitor_widget_->setLogicTrace(trace);
  334. }
  335. }