#pragma once #include "domain/register_monitor_model.h" #include "domain/register_repository.h" #include #include #include #include class VirtualRegisterRepository; // 自由监控列表编辑的失败分类 enum class RegisterMonitorError { None, // 操作成功 InvalidAddress, // 起始地址格式或区域不支持 RangeOverflow, // 连续范围超出 M/D 地址上限 LimitExceeded, // 监控地址数量超过会话上限 NoChange // 操作没有产生任何列表变化 }; // 监控列表编辑结果;affectedCount 表示本次受影响的地址数量 struct RegisterMonitorResult { bool succeeded = false; // 列表编辑是否成功 RegisterMonitorError error = RegisterMonitorError::None; // 失败时的分类 std::string message; // 面向用户的 UTF-8 成功说明或失败原因 int affectedCount = 0; // 本次新增或删除的地址数量 }; // 自由监控写入结果;底层 RegisterError 会原样保留 struct RegisterMonitorWriteResult { bool succeeded = false; // 写入请求是否成功提交 RegisterError error = RegisterError::Unavailable; // 底层仓库错误分类 std::string message; // 面向用户的 UTF-8 错误说明 }; /** * @brief 编排自由监控地址列表和寄存器仓库读写 * * 地址列表和离线初始值只属于当前运行会话,不写入工程文件;仓库由当前运行模式注入 */ class RegisterMonitorService { public: /** * @brief 创建自由监控服务 * @param repository 当前运行模式使用的寄存器仓库,不由服务拥有 */ explicit RegisterMonitorService(RegisterRepository &repository); // 配置编辑态离线初始值仓库;该仓库只保存在当前进程内 void setOfflineInitialRepository(VirtualRegisterRepository &repository); // 编辑态开启时,监控写入同时更新离线初始值 void setOfflineInitialCaptureEnabled(bool enabled); /** * @brief 从起始地址连续添加同一区域的多个地址 * @param start_address 文本地址,例如 M0 或 D100 * @param count 连续地址数量,必须为正且不能越过 4000 * @return 去重后实际新增数量;格式、范围、容量或无变化时返回失败 */ RegisterMonitorResult addRange(const std::string &start_address, int count); RegisterMonitorResult addRange( const std::string &start_address, int count, RegisterDataType data_type); /** * @brief 删除一批监控地址 * @param addresses 待删除地址;不存在的地址会被忽略 * @return 实际删除数量,并在发生变化时通知轮询集合更新 */ RegisterMonitorResult remove(const std::vector &addresses); RegisterMonitorResult remove(const std::vector &points); /** * @brief 清空当前会话的监控地址列表 * @return 实际清除数量;列表本来为空时返回 NoChange */ RegisterMonitorResult clear(); /** * @brief 对单个 M 地址提交位写入 * @param address 必须是有效的 M 区地址 * @param value 要写入的位值 * @return 成功或包含底层 RegisterError 和用户可读文本的失败结果 */ RegisterMonitorWriteResult writeBit(const RegisterAddress &address, bool value); /** * @brief 对单个 D 地址提交有符号 16 位字写入 * @param address 必须是有效的 D 区地址 * @param value 要写入的 D 字值 * @return 成功或包含底层 RegisterError 和用户可读文本的失败结果 */ RegisterMonitorWriteResult writeWord( const RegisterAddress &address, std::int16_t value); RegisterMonitorWriteResult writeFloat( const RegisterAddress &address, float value); /** * @brief 返回当前会话的监控地址列表 * @return 按服务内部顺序保存的只读地址列表 */ const std::vector &addresses() const; const std::vector &points() const; std::vector pollAddresses() const; std::vector float32Starts() const; /** * @brief 读取监控列表的当前值并生成 UI 展示模型 * @param communication_fault 通信处于故障态时,将成功读回值标记为通信故障 * @return 每个监控地址对应一个值和可用性状态 */ std::vector values(bool communication_fault) const; /** * @brief 设置监控地址变化通知回调 * @param callback 地址列表新增、删除或清空后调用;可传空函数取消通知 */ void setAddressesChangedCallback(std::function callback); private: RegisterMonitorWriteResult captureInitialBit( const RegisterAddress &address, bool value, const RegisterMonitorWriteResult &active_result); RegisterMonitorWriteResult captureInitialWord( const RegisterAddress &address, std::int16_t value, const RegisterMonitorWriteResult &active_result); RegisterMonitorWriteResult captureInitialFloat( const RegisterAddress &address, float value, const RegisterMonitorWriteResult &active_result); RegisterRepository &repository_; // 当前运行模式的寄存器仓库,不由服务拥有 VirtualRegisterRepository *offline_initial_repository_ = nullptr; bool capture_offline_initial_values_ = false; RegisterMonitorModel model_; // 当前会话的去重监控地址列表 std::function addresses_changed_callback_; // 地址变化后的轮询刷新通知 };