/** * @file runtime_mode_service.h * @brief 定义面向 UI 的运行模式服务契约 * @version 0.1.0 * @author suyu * @date 2026-08-08 */ #pragma once #include "domain/runtime_state.h" #include "offline_simulation_service.h" #include "online_logic_monitor_service.h" #include "plc_communication_gateway.h" #include #include #include class ProjectService; class ActiveRegisterRepository; class RegisterRepository; // 隔离 UI 与领域状态机,并编排寄存器仓库切换和进入真机的前置条件 class RuntimeModeService { public: /** * @brief 创建运行模式服务 * @param project_service 只读工程服务,用于运行前校验和收集轮询地址 * @param offline_simulation_service 离线仿真服务,由应用层负责其生命周期 */ RuntimeModeService( const ProjectService &project_service, OfflineSimulationService &offline_simulation_service, OnlineLogicMonitorService &online_logic_monitor_service); /** * @brief 解除 PLC 网关回调绑定 */ ~RuntimeModeService(); /** @brief 获取当前应用运行模式 */ ApplicationMode mode() const; /** * @brief 获取当前模式下允许的工程编辑和寄存器使用策略 * @return 与当前运行模式对应的能力策略 */ ModePolicy policy() const; /** * @brief 退出离线或真机运行态并返回编辑态 * @return 已处于编辑态或状态机拒绝切换时返回失败结果 */ ModeTransitionResult enterEditing(); /** * @brief 从编辑态进入离线运行态 * @return 非编辑态进入时返回必须先回到编辑态的失败结果 */ ModeTransitionResult enterOfflineRunning(); /** * @brief 从编辑态进入真机运行态 * @return 未完成 PLC 初次读取或非编辑态进入时返回失败结果 */ ModeTransitionResult enterOnlineRunning(); /** * @brief 更新 PLC 是否已完成首次有效读取 * @param completed 为 true 时允许在编辑态进入真机运行模式 * * 由 PLC 通信服务在首次读取成功或缓存失效时调用 */ void setInitialPlcReadCompleted(bool completed); /** * @brief 查询 PLC 是否已完成首次有效读取 * @return 已建立可用于进入真机运行态的 PLC 缓存时返回 true */ bool initialPlcReadCompleted() const; /** @brief 获取离线仿真当前状态 */ SimulationState simulationState() const; /** @brief 获取离线仿真成功完成的扫描轮数 */ std::uint64_t successfulScanCount() const; /** @brief 获取离线仿真最近一次扫描错误 */ const LogicScanResult &simulationError() const; /** @brief 返回服务持有的离线仿真服务引用 */ OfflineSimulationService &offlineSimulationService(); OnlineLogicMonitorService &onlineLogicMonitorService(); /** * @brief 注入 PLC 网关、活动仓库和两种实际数据源 * * 应用生命周期内只调用一次;真机模式使用 PLC 仓库,编辑/离线模式使用虚拟仓库 */ void configurePlc( PlcCommunicationGateway &gateway, ActiveRegisterRepository &active_repository, RegisterRepository &virtual_repository, RegisterRepository &plc_repository); /** * @brief 连接 PLC 并开始异步通信 * @param configuration 串口、Modbus 和轮询配置 * @return 连接请求受理结果,不阻塞 UI 等待首读完成 */ PlcCommunicationResult connectPlc(const PlcSerialConfiguration &configuration); /** * @brief 设置自由监控引用的地址并刷新 PLC 轮询集合 * @param addresses 自由监控当前需要读取的 M/D 地址 */ void setMonitorAddresses(const std::vector &addresses); void setMonitorAddresses( const std::vector &addresses, const std::vector &float32_starts); /** * @brief 汇总工程和自由监控引用并刷新 PLC 轮询地址 * @return 网关未配置或地址数量超限时返回失败结果 */ PlcCommunicationResult refreshPlcPollAddresses(); /** * @brief 退出真机运行、断开 PLC 并清除首读资格 */ void disconnectPlc(); /** @brief 获取当前 PLC 连接状态;网关未配置时返回 Disconnected */ PlcConnectionState plcConnectionState() const; /** @brief 获取 PLC 最近一次通信错误文本;网关未配置时返回空字符串 */ const std::string &plcError() const; /** * @brief 设置 PLC 状态变化通知回调 * @param callback 状态、首读资格或通信错误变化时调用的函数;可传空函数取消通知 */ void setPlcStatusChangedCallback(std::function callback); private: const ProjectService &project_service_; // 不拥有的只读工程服务 OfflineSimulationService &offline_simulation_service_; // 不拥有的离线仿真服务 OnlineLogicMonitorService &online_logic_monitor_service_; // 不拥有的真机只读轨迹服务 RuntimeState state_; // 编辑、离线和真机模式状态机 // PLC 缓存是否已通过有效首读建立,通信故障时清除 bool initial_plc_read_completed_ = false; PlcCommunicationGateway *plc_gateway_ = nullptr; // 不拥有的 PLC 通信网关 ActiveRegisterRepository *active_repository_ = nullptr; // 当前模式使用的仓库代理 RegisterRepository *virtual_repository_ = nullptr; // 离线/编辑模式的虚拟仓库 RegisterRepository *plc_repository_ = nullptr; // 真机模式的 PLC 缓存仓库 std::function plc_status_changed_callback_; // PLC 状态变化通知 std::vector monitor_addresses_; // 自由监控额外引用的地址 std::vector monitor_float32_starts_; // 自由监控中的 Float32 起始地址 };