综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

401 lines
14 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_.pollAddresses(),
  98. register_monitor_service_.float32Starts());
  99. runtime_monitor_widget_->refreshValues(
  100. runtime_mode_service_.mode(),
  101. runtime_mode_service_.plcConnectionState());
  102. });
  103. QObject::connect(runtime_monitor_widget_->freeMonitorWidget(),
  104. &FreeMonitorWidget::operationMessage,
  105. &parent_, [this](const QString &message)
  106. {
  107. status_reporter_(message, 4000);
  108. });
  109. QObject::connect(runtime_monitor_widget_, &RuntimeMonitorWidget::navigationFailed,
  110. &parent_, [this](const QString &message)
  111. {
  112. status_reporter_(message, 5000);
  113. output_reporter_(QObject::tr("页面导航失败:%1").arg(message));
  114. });
  115. QObject::connect(runtime_monitor_widget_,
  116. &RuntimeMonitorWidget::modeChangeRequested,
  117. &parent_,
  118. [this](int mode)
  119. {
  120. if (mode_requester_)
  121. {
  122. mode_requester_(mode);
  123. }
  124. });
  125. QObject::connect(runtime_monitor_widget_,
  126. &RuntimeMonitorWidget::plcConfigurationRequested,
  127. &parent_,
  128. [this]
  129. {
  130. if (plc_configuration_requester_)
  131. {
  132. plc_configuration_requester_();
  133. }
  134. });
  135. QObject::connect(runtime_monitor_widget_,
  136. &RuntimeMonitorWidget::plcDisconnectRequested,
  137. &parent_,
  138. [this]
  139. {
  140. if (plc_disconnect_requester_)
  141. {
  142. plc_disconnect_requester_();
  143. }
  144. });
  145. runtime_refresh_timer_ = new QTimer(&parent_);
  146. runtime_refresh_timer_->setInterval(150);
  147. QObject::connect(runtime_refresh_timer_, &QTimer::timeout,
  148. &parent_, [this] { handleRuntimeTimer(); });
  149. runtime_refresh_timer_->start();
  150. QObject::connect(&runtime_mode_service_.offlineSimulationService(),
  151. &OfflineSimulationService::stateChanged,
  152. &parent_, [this] { handleSimulationStateChanged(); },
  153. Qt::QueuedConnection);
  154. QObject::connect(&runtime_mode_service_.offlineSimulationService(),
  155. &OfflineSimulationService::scanCompleted,
  156. &parent_, [this] { handleScanCompleted(); },
  157. Qt::QueuedConnection);
  158. QObject::connect(&runtime_mode_service_.onlineLogicMonitorService(),
  159. &OnlineLogicMonitorService::stateChanged,
  160. &parent_, [this] { handleSimulationStateChanged(); });
  161. QObject::connect(&runtime_mode_service_.onlineLogicMonitorService(),
  162. &OnlineLogicMonitorService::scanCompleted,
  163. &parent_, [this] { handleScanCompleted(); },
  164. Qt::QueuedConnection);
  165. }
  166. void RuntimePanelController::configureUserRuntimeMode(
  167. bool enabled,
  168. std::function<void(int)> mode_requester,
  169. std::function<void()> plc_configuration_requester,
  170. std::function<void()> plc_disconnect_requester)
  171. {
  172. mode_requester_ = std::move(mode_requester);
  173. plc_configuration_requester_ = std::move(plc_configuration_requester);
  174. plc_disconnect_requester_ = std::move(plc_disconnect_requester);
  175. if (runtime_monitor_widget_ != nullptr)
  176. {
  177. runtime_monitor_widget_->setUserRuntimeMode(enabled);
  178. }
  179. }
  180. RuntimeMonitorWidget *RuntimePanelController::runtimeMonitorWidget() const
  181. {
  182. return runtime_monitor_widget_;
  183. }
  184. void RuntimePanelController::enterRuntime(
  185. const std::string &page_id,
  186. const std::string &logic_id,
  187. ApplicationMode mode,
  188. PlcConnectionState plc_state)
  189. {
  190. if (!runtime_session_active_)
  191. {
  192. runtime_monitor_widget_->setProjectObjects(page_id, logic_id);
  193. // 运行窗口只创建一次,后续进入运行态复用同一个监控投影
  194. runtime_session_active_ = true;
  195. }
  196. runtime_monitor_widget_->freeMonitorWidget()->reloadAddresses();
  197. runtime_monitor_widget_->setMode(mode, plc_state);
  198. runtime_monitor_window_->setWindowTitle(
  199. fromUtf8(project_service_.project().metadata.name));
  200. runtime_monitor_window_->showForRuntime();
  201. }
  202. void RuntimePanelController::leaveRuntime(
  203. ApplicationMode mode, PlcConnectionState plc_state)
  204. {
  205. runtime_session_active_ = false;
  206. runtime_monitor_widget_->setMode(mode, plc_state);
  207. runtime_monitor_window_->hideForEditing();
  208. }
  209. void RuntimePanelController::closeForApplicationExit()
  210. {
  211. if (runtime_monitor_window_ != nullptr)
  212. {
  213. runtime_monitor_window_->closeForApplicationExit();
  214. }
  215. }
  216. void RuntimePanelController::updateSimulationUi(bool report_fault)
  217. {
  218. const bool offline = runtime_mode_service_.mode()
  219. == ApplicationMode::OfflineRunning;
  220. const bool online = runtime_mode_service_.mode()
  221. == ApplicationMode::OnlineRunning;
  222. const bool plc_connected = runtime_mode_service_.plcConnectionState()
  223. == PlcConnectionState::Connected;
  224. const SimulationState state = runtime_mode_service_.simulationState();
  225. const bool write_enabled = (online && plc_connected)
  226. || (offline && state == SimulationState::Running);
  227. // 编辑画布始终只读,运行操作统一由运行监控中的 HMI 发出
  228. hmi_editor_widget_.setRuntimeWriteEnabled(false);
  229. if (runtime_monitor_widget_ != nullptr)
  230. {
  231. runtime_monitor_widget_->setHmiWriteEnabled(write_enabled);
  232. runtime_monitor_widget_->setFreeMonitorWriteEnabled(write_enabled);
  233. runtime_monitor_widget_->refreshValues(
  234. runtime_mode_service_.mode(),
  235. runtime_mode_service_.plcConnectionState());
  236. }
  237. if (online)
  238. {
  239. switch (runtime_mode_service_.onlineLogicMonitorService().state())
  240. {
  241. case OnlineLogicMonitorState::Running:
  242. {
  243. executor_status_label_.setText(
  244. QObject::tr("本地推算轨迹:运行(%1 次)")
  245. .arg(runtime_mode_service_.onlineLogicMonitorService()
  246. .successfulScanCount()));
  247. return;
  248. }
  249. case OnlineLogicMonitorState::Faulted:
  250. {
  251. executor_status_label_.setText(QObject::tr("本地推算轨迹:故障"));
  252. if (report_fault)
  253. {
  254. const LogicScanResult &error = runtime_mode_service_
  255. .onlineLogicMonitorService().lastError();
  256. const QString message = QObject::tr("真机本地轨迹异常:%1")
  257. .arg(fromUtf8(error.message));
  258. status_reporter_(message, 0);
  259. output_reporter_(message);
  260. }
  261. return;
  262. }
  263. case OnlineLogicMonitorState::Stopped:
  264. default:
  265. {
  266. executor_status_label_.setText(QObject::tr("本地推算轨迹:停止"));
  267. return;
  268. }
  269. }
  270. }
  271. switch (state)
  272. {
  273. case SimulationState::Running:
  274. {
  275. executor_status_label_.setText(
  276. QObject::tr("逻辑执行器:运行(%1 次)")
  277. .arg(runtime_mode_service_.successfulScanCount()));
  278. break;
  279. }
  280. case SimulationState::Faulted:
  281. {
  282. executor_status_label_.setText(QObject::tr("逻辑执行器:故障"));
  283. if (!report_fault)
  284. {
  285. break;
  286. }
  287. const LogicScanResult &error = runtime_mode_service_.simulationError();
  288. if (!error.logicId.empty()
  289. && logic_editor_service_.findLogic(error.logicId) != nullptr)
  290. {
  291. select_logic_(error.logicId);
  292. }
  293. const std::string logic_id = current_logic_id_();
  294. logic_editor_widget_.setLogicId(logic_id);
  295. if (runtime_monitor_widget_ != nullptr)
  296. {
  297. runtime_monitor_widget_->setProjectObjects(
  298. hmi_navigation_service_.currentPageId(), logic_id);
  299. }
  300. logic_editor_widget_.setRuntimeTrace(
  301. runtime_mode_service_.offlineSimulationService().traceSnapshot(),
  302. error.nodeId);
  303. if (runtime_monitor_widget_ != nullptr)
  304. {
  305. runtime_monitor_widget_->setLogicTrace(
  306. runtime_mode_service_.offlineSimulationService().traceSnapshot(),
  307. error.nodeId);
  308. }
  309. if (!error.nodeId.empty())
  310. {
  311. logic_editor_widget_.selectNode(error.nodeId);
  312. show_logic_properties_(error.nodeId);
  313. }
  314. QString message = QObject::tr("离线仿真异常:%1").arg(fromUtf8(error.message));
  315. if (!error.logicId.empty())
  316. {
  317. message += QObject::tr(",逻辑 %1").arg(fromUtf8(error.logicId));
  318. }
  319. if (!error.rungId.empty())
  320. {
  321. message += QObject::tr(",网络 %1").arg(fromUtf8(error.rungId));
  322. }
  323. if (!error.nodeId.empty())
  324. {
  325. message += QObject::tr(",节点 %1").arg(fromUtf8(error.nodeId));
  326. }
  327. status_reporter_(message, 0);
  328. output_reporter_(message);
  329. break;
  330. }
  331. case SimulationState::Stopped:
  332. default:
  333. {
  334. executor_status_label_.setText(QObject::tr("逻辑执行器:停止"));
  335. break;
  336. }
  337. }
  338. }
  339. void RuntimePanelController::handleRuntimeTimer()
  340. {
  341. // 定时器只刷新投影;离线按定时器扫描,真机在完整 PLC 轮询后推算
  342. if (runtime_mode_service_.mode() == ApplicationMode::Editing)
  343. {
  344. return;
  345. }
  346. alarm_service_.refresh();
  347. hmi_editor_widget_.refreshRuntimeValues();
  348. if (runtime_monitor_widget_ != nullptr)
  349. {
  350. runtime_monitor_widget_->refreshValues(
  351. runtime_mode_service_.mode(),
  352. runtime_mode_service_.plcConnectionState());
  353. }
  354. updateSimulationUi(false);
  355. }
  356. void RuntimePanelController::handleSimulationStateChanged()
  357. {
  358. updateSimulationUi(true);
  359. }
  360. void RuntimePanelController::handleScanCompleted()
  361. {
  362. const ApplicationMode mode = runtime_mode_service_.mode();
  363. const bool offline_running = mode == ApplicationMode::OfflineRunning
  364. && runtime_mode_service_.simulationState() == SimulationState::Running;
  365. const bool online_running = mode == ApplicationMode::OnlineRunning
  366. && runtime_mode_service_.onlineLogicMonitorService().state()
  367. == OnlineLogicMonitorState::Running;
  368. // 排队信号可能晚于退出操作到达,编辑态不得恢复旧运行轨迹
  369. if (!offline_running && !online_running)
  370. {
  371. return;
  372. }
  373. const std::string logic_id = current_logic_id_();
  374. const LogicTraceSnapshot &trace = offline_running
  375. ? runtime_mode_service_.offlineSimulationService().traceSnapshot()
  376. : runtime_mode_service_.onlineLogicMonitorService().traceSnapshot();
  377. logic_editor_widget_.setRuntimeTrace(trace);
  378. if (runtime_monitor_widget_ != nullptr)
  379. {
  380. runtime_monitor_widget_->setLogicTrace(trace);
  381. }
  382. }